From patchwork Tue Aug 21 15:56:56 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 10571917 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 03D6317E0 for ; Tue, 21 Aug 2018 15:57:00 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E7DF82A966 for ; Tue, 21 Aug 2018 15:56:59 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id DC2C32A97A; Tue, 21 Aug 2018 15:56:59 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 80E6F2A976 for ; Tue, 21 Aug 2018 15:56:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727587AbeHUTRk (ORCPT ); Tue, 21 Aug 2018 15:17:40 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:54748 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726967AbeHUTRk (ORCPT ); Tue, 21 Aug 2018 15:17:40 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id D76727A7E7; Tue, 21 Aug 2018 15:56:57 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-123-147.rdu2.redhat.com [10.10.123.147]) by smtp.corp.redhat.com (Postfix) with ESMTP id E2CCC10CD65A; Tue, 21 Aug 2018 15:56:56 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 01/23] TPM: Add new TPMs to the tail of the list to prevent inadvertent change of dev From: David Howells To: denkenz@gmail.com, jarkko.sakkinen@linux.intel.com, jejb@linux.vnet.ibm.com Cc: keyrings@vger.kernel.org, linux-integrity@vger.kernel.org, tpmdd-devel@lists.sourceforge.net, linux-security-module@vger.kernel.org Date: Tue, 21 Aug 2018 16:56:56 +0100 Message-ID: <153486701644.13066.13372706238885253812.stgit@warthog.procyon.org.uk> In-Reply-To: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> References: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Tue, 21 Aug 2018 15:56:57 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Tue, 21 Aug 2018 15:56:57 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'dhowells@redhat.com' RCPT:'' Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Add newly registered TPMs to the tail of the list, not the beginning, so that things that are specifying TPM_ANY_NUM don't find that the device they're using has inadvertently changed. Adding a second device would break IMA, for instance. Signed-off-by: David Howells Reviewed-by: Jason Gunthorpe Signed-off-by: Peter Huewe cc: stable@vger.kernel.org --- drivers/char/tpm/tpm-interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 6af17002a115..cfb9089887bd 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -1122,7 +1122,7 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, /* Make chip available */ spin_lock(&driver_lock); - list_add_rcu(&chip->list, &tpm_chip_list); + list_add_tail_rcu(&chip->list, &tpm_chip_list); spin_unlock(&driver_lock); return chip; From patchwork Tue Aug 21 15:57:03 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 10571921 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 6CB2F17E0 for ; Tue, 21 Aug 2018 15:57:10 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5A6942A7D1 for ; Tue, 21 Aug 2018 15:57:10 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 4E7B12A976; Tue, 21 Aug 2018 15:57:10 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 28C8D2A966 for ; Tue, 21 Aug 2018 15:57:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728077AbeHUTRt (ORCPT ); Tue, 21 Aug 2018 15:17:49 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:53874 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726967AbeHUTRt (ORCPT ); Tue, 21 Aug 2018 15:17:49 -0400 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id A0AEF8076825; Tue, 21 Aug 2018 15:57:04 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-123-147.rdu2.redhat.com [10.10.123.147]) by smtp.corp.redhat.com (Postfix) with ESMTP id 7BBF9A9A06; Tue, 21 Aug 2018 15:57:03 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 02/23] TPM: Provide a facility for a userspace TPM emulator From: David Howells To: denkenz@gmail.com, jarkko.sakkinen@linux.intel.com, jejb@linux.vnet.ibm.com Cc: keyrings@vger.kernel.org, linux-integrity@vger.kernel.org, tpmdd-devel@lists.sourceforge.net, linux-security-module@vger.kernel.org Date: Tue, 21 Aug 2018 16:57:03 +0100 Message-ID: <153486702302.13066.15889029286852815542.stgit@warthog.procyon.org.uk> In-Reply-To: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> References: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Tue, 21 Aug 2018 15:57:04 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Tue, 21 Aug 2018 15:57:04 +0000 (UTC) for IP:'10.11.54.5' DOMAIN:'int-mx05.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'dhowells@redhat.com' RCPT:'' Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Provide a misc device file (/dev/tpm_emul) by which a userspace TPM emulator can set up a virtual TPM device under the control of the TPM frontend. The way this works is: (1) The emulator opens /dev/tpm_emul which is provided by the tpm_user driver. (2) tpm_user registers a TPM device and the tpm driver creates a /dev/tpmN misc device for the trousers package and suchlike to access. (3) The emulator sits in read() on the emulator device waiting for a command to come through. (4) tpm_user passes requests from /dev/tpmN to the emulator's read() call. (5) The emulator processes the request. (6) The emulator either write()'s the reply or calls ioctl(fd,0,0) to cancel the command. (7) The emulator goes back to read() to wait for the next command. (8) tpm_user passes the reply back to the tpm driver which passes it back to /dev/tpmN. When the emulator closes /dev/tpm_emul, the TPM driver is unregistered and the /dev/tpmN misc device is then removed. Any outstanding requests are aborted and -EIO will be returned from then on. Multiple TPMs can be registered. Signed-off-by: David Howells --- drivers/char/tpm/Kconfig | 13 + drivers/char/tpm/Makefile | 1 drivers/char/tpm/tpm_user_emul.c | 672 ++++++++++++++++++++++++++++++++++++++ include/linux/wait.h | 11 + 4 files changed, 697 insertions(+) create mode 100644 drivers/char/tpm/tpm_user_emul.c diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index c54cac3f8bc8..c33ebd8504ec 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -122,4 +122,17 @@ config TCG_XEN To compile this driver as a module, choose M here; the module will be called xen-tpmfront. +config TCG_USER_EMUL + tristate "Userspace TPM emulation interface for development purposes" + depends on DEBUG_KERNEL + ---help--- + Provide a userspace TPM emulation interface through a misc device + interface (/dev/tpm_emul). This can be used to enable development of + TPM-based services by providing a target TPM that can be safely + trashed or for computers that don't have a physical TPM. + + This driver should _NOT_ be included in production kernels as it + might be possible to use it to fool various kernel security features + (such as IMA). + endif # TCG_TPM diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index 4d85dd681b81..b179052cd81b 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile @@ -22,3 +22,4 @@ obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o obj-$(CONFIG_TCG_IBMVTPM) += tpm_ibmvtpm.o obj-$(CONFIG_TCG_ST33_I2C) += tpm_i2c_stm_st33.o obj-$(CONFIG_TCG_XEN) += xen-tpmfront.o +obj-$(CONFIG_TCG_USER_EMUL) += tpm_user_emul.o diff --git a/drivers/char/tpm/tpm_user_emul.c b/drivers/char/tpm/tpm_user_emul.c new file mode 100644 index 000000000000..b96350592bca --- /dev/null +++ b/drivers/char/tpm/tpm_user_emul.c @@ -0,0 +1,672 @@ +/* TPM userspace emulation driver + * + * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#define pr_fmt(fmt) "TPM_USER: "fmt +#include +#include +#include +#include +#include +#include +#include +#include +#include "tpm.h" + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("David Howells "); + +#define TIS_SHORT_TIMEOUT 750 /* ms */ +#define TIS_LONG_TIMEOUT 2000 /* 2 sec */ + +#define kenter(FMT, ...) \ + pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__) +#define kleave(FMT, ...) \ + pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__) + +/* + * Packet of data going to/from the TPM. We only permit one command + * at a time, so we don't need to deal with chains of packets. + */ +struct tpm_user_packet { + unsigned size; + unsigned cancellation; + u8 buffer[]; +}; + +/* + * Emulator state. + */ +enum tpm_user_status { + TPM_USER_INITIALISING, + TPM_USER_IDLE, + TPM_USER_SENDING, + TPM_USER_AWAITING_REPLY, + TPM_USER_CANCELLING, + TPM_USER_GOT_REPLY, + TPM_USER_CANCELLED, + TPM_USER_EIO, +}; + +struct tpm_user_state { + struct work_struct initialiser_work; + struct completion initialiser_done; + struct file *file; + struct platform_device *pdev; + struct tpm_chip *chip; + wait_queue_head_t wq; + struct tpm_user_packet *to_emulator_q; + struct tpm_user_packet *from_emulator_q; + spinlock_t lock; + enum tpm_user_status status; + int initialiser_error; +}; + +/* + * Read the emulator status. + */ +static u8 tpm_user_status(struct tpm_chip *chip) +{ + struct tpm_user_state *state = chip->vendor.priv; + enum tpm_user_status status = ACCESS_ONCE(state->status); + + if (status == TPM_USER_GOT_REPLY) + return 1; + if (status == TPM_USER_CANCELLED || + status == TPM_USER_EIO) + return 2; + return 0; +} + +/* + * Find out if a request has been cancelled. + */ +static bool tpm_user_is_req_cancelled(struct tpm_chip *chip, u8 status) +{ + struct tpm_user_state *state = chip->vendor.priv; + struct tpm_user_packet *pkt = NULL; + + if (status != 2) + return false; + + spin_lock(&state->lock); + if (state->status == TPM_USER_CANCELLED) { + pkt = state->from_emulator_q; + state->from_emulator_q = NULL; + state->status = TPM_USER_IDLE; + } + spin_unlock(&state->lock); + kfree(pkt); + return true; +} + +/* + * Send data to the emulator. + */ +static int tpm_user_send(struct tpm_chip *chip, u8 *buf, size_t len) +{ + struct tpm_user_state *state = chip->vendor.priv; + struct tpm_user_packet *pkt; + int ret; + + kenter(",%*phN,%zu", min_t(int, len, 16), buf, len); + + pkt = kmalloc(sizeof(struct tpm_user_packet) + len, GFP_KERNEL); + if (!pkt) + return -ENOMEM; + pkt->size = len; + memcpy(pkt->buffer, buf, len); + + spin_lock(&state->lock); + switch (state->status) { + case TPM_USER_IDLE: + state->to_emulator_q = pkt; + state->status = TPM_USER_SENDING; + ret = 0; + break; + default: + dev_err(chip->dev, "Sending in state %u\n", state->status); + case TPM_USER_EIO: + kfree(pkt); + ret = -EIO; + break; + } + spin_unlock(&state->lock); + if (ret == 0) + wake_up(&state->wq); + return ret; +} + +/* + * Allow the TPM emulator to read requests from the driver + */ +static ssize_t tpm_user_read(struct file *file, char __user *buffer, + size_t buflen, loff_t *pos) +{ + struct tpm_user_state *state = file->private_data; + struct tpm_user_packet *pkt; + unsigned long copied; + ssize_t ret; + + kenter("{%u},,%zu,", state->status, buflen); + +again: + mutex_lock(&file_inode(file)->i_mutex); + + ret = -EAGAIN; + spin_lock(&state->lock); + if (state->status == TPM_USER_EIO) { + ret = -EIO; + goto out; + } + + if (state->status != TPM_USER_SENDING) { + if (file->f_flags & O_NONBLOCK) + goto out; + pr_devel("sleeping\n"); + wait_event_cmd_interruptible( + state->wq, + state->status == TPM_USER_SENDING || + state->status == TPM_USER_EIO, + spin_unlock(&state->lock), + spin_lock(&state->lock)); + pr_devel("woken\n"); + + ret = -ERESTARTSYS; + if (signal_pending(current)) + goto out; + ret = -EIO; + if (state->status == TPM_USER_EIO) + goto out; + } + + pkt = state->to_emulator_q; + pr_devel("dequeued send(%u)\n", pkt->size); + ret = -EMSGSIZE; + if (pkt->size > buflen) + goto out; + + /* Claim responsibility for the packet. */ + state->status = TPM_USER_AWAITING_REPLY; + state->to_emulator_q = NULL; + spin_unlock(&state->lock); + + copied = copy_to_user(buffer, pkt->buffer, pkt->size); + spin_lock(&state->lock); + + if (copied != 0) { + /* Ugh - the emulator went splat. Discard the request and + * reject all further requests. */ + kfree(pkt); + dev_err(state->chip->dev, "Emulator EFAULT in read\n"); + state->status = TPM_USER_EIO; + ret = -EFAULT; + } else if (state->status == TPM_USER_CANCELLING) { + pr_devel("cancel\n"); + state->status = TPM_USER_CANCELLED; + ret = -ECANCELED; + } else { + ret = pkt->size; + } + +out: + spin_unlock(&state->lock); + mutex_unlock(&file_inode(file)->i_mutex); + if (ret == -ECANCELED) + goto again; + kleave(" = %zd", ret); + return ret; +} + +/* + * Allow the TPM emulator to respond to requests + * + * The buffer is should contain a packet with at least TPM_HEADER_SIZE bytes of + * data in it. + */ +static ssize_t tpm_user_write(struct file *file, + const char __user *data, + size_t datalen, + loff_t *pos) +{ + struct tpm_user_state *state = file->private_data; + struct tpm_user_packet *pkt; + unsigned expected; + __be32 tmpbe; + ssize_t ret; + + kenter("{%u},,%zu,", state->status, datalen); + + /* Sanity checking the reply before we get any locks. */ + if (datalen == 0) { + dev_err(state->chip->dev, "Empty reply\n"); + return -EMSGSIZE; + } + + if (datalen < TPM_HEADER_SIZE) { + dev_err(state->chip->dev, "Data packet missing TPM header\n"); + return -EMSGSIZE; + } + + pkt = kmalloc(sizeof(struct tpm_user_packet) + datalen, GFP_KERNEL); + if (!pkt) + return -ENOMEM; + pkt->size = datalen; + ret = -EFAULT; + if (copy_from_user(pkt->buffer, data, datalen) != 0) + goto err_free; + + pr_debug("got reply %*phN\n", min_t(int, datalen, 16), pkt->buffer); + + memcpy(&tmpbe, pkt->buffer + 2, sizeof(tmpbe)); + expected = be32_to_cpu(tmpbe); + if (expected != datalen) { + dev_err(state->chip->dev, "Data packet size (%zu) != expected (%x)\n", + datalen, expected); + ret = -EMSGSIZE; + goto err_free; + } + + mutex_lock(&file_inode(file)->i_mutex); + spin_lock(&state->lock); + + switch (state->status) { + case TPM_USER_AWAITING_REPLY: + BUG_ON(state->from_emulator_q != NULL); + state->from_emulator_q = pkt; + state->status = TPM_USER_GOT_REPLY; + pkt = NULL; + ret = datalen; + break; + + case TPM_USER_CANCELLING: + state->status = TPM_USER_CANCELLED; + ret = -ECANCELED; + break; + + case TPM_USER_EIO: + ret = -EIO; + break; + + default: + dev_err(state->chip->dev, "Reply unexpected in state (%u)\n", + state->status); + ret = -EPROTO; + break; + } + + spin_unlock(&state->lock); + mutex_unlock(&file_inode(file)->i_mutex); + if (ret != -EPROTO) + wake_up(&state->wq); +err_free: + kfree(pkt); + kleave(" = %zd", ret); + return ret; +} + +/* + * Allow the TPM emulator to cancel a request with ioctl(fd,0,0). + */ +static long tpm_user_ioctl(struct file *file, unsigned cmd, unsigned long data) +{ + struct tpm_user_state *state = file->private_data; + long ret; + + kenter("{%u},%x,%lx", state->status, cmd, data); + + if (cmd != 0 && data != 0) + return -ENOIOCTLCMD; + + mutex_lock(&file_inode(file)->i_mutex); + spin_lock(&state->lock); + + switch (state->status) { + case TPM_USER_AWAITING_REPLY: + case TPM_USER_CANCELLING: + state->status = TPM_USER_CANCELLED; + ret = 0; + break; + + case TPM_USER_EIO: + ret = -EIO; + break; + + default: + dev_err(state->chip->dev, + "Cancellation unexpected in state (%u)\n", + state->status); + ret = -EPROTO; + break; + } + + spin_unlock(&state->lock); + mutex_unlock(&file_inode(file)->i_mutex); + wake_up(&state->wq); + kleave(" = %ld", ret); + return ret; +} + +/* + * Receive data from the emulator. + */ +static int tpm_user_recv(struct tpm_chip *chip, u8 *buf, size_t count) +{ + struct tpm_user_state *state = chip->vendor.priv; + struct tpm_user_packet *pkt; + int ret; + + kenter("{%u},,%zu", state->status, count); + + spin_lock(&state->lock); + + pkt = state->from_emulator_q; + state->from_emulator_q = NULL; + switch (state->status) { + case TPM_USER_GOT_REPLY: + state->status = TPM_USER_IDLE; + BUG_ON(!pkt); + ret = pkt->size; + break; + + case TPM_USER_CANCELLED: + state->status = TPM_USER_IDLE; + ret = -ECANCELED; + break; + + case TPM_USER_EIO: + ret = -EIO; + break; + + default: + dev_err(chip->dev, "TPM data recv in unexpected state (%u)\n", + state->status); + ret = -EIO; + break; + } + + spin_unlock(&state->lock); + + if (pkt) { + if (ret > 0) { + if (pkt->size > count) { + dev_err(chip->dev, "Received excess data\n"); + ret = -EIO; + } else { + memcpy(buf, pkt->buffer, pkt->size); + } + } + kfree(pkt); + } + + kleave(" = %d", ret); + return ret; +} + +/* + * Abort the current request. + */ +static void tpm_user_cancel(struct tpm_chip *chip) +{ + struct tpm_user_state *state = chip->vendor.priv; + + kenter("{%u}", state->status); + + spin_lock(&state->lock); + + switch (state->status) { + case TPM_USER_SENDING: + case TPM_USER_AWAITING_REPLY: + case TPM_USER_GOT_REPLY: + kfree(state->to_emulator_q); + state->to_emulator_q = NULL; + kfree(state->from_emulator_q); + state->from_emulator_q = NULL; + state->status = TPM_USER_CANCELLING; + break; + default: + break; + } + + if (state->status == TPM_USER_CANCELLING) { + DECLARE_WAITQUEUE(waiter, current); + + for (;;) { + prepare_to_wait(&state->wq, + &waiter, TASK_UNINTERRUPTIBLE); + if (state->status == TPM_USER_CANCELLED || + state->status == TPM_USER_EIO) + break; + spin_unlock(&state->lock); + schedule_timeout(10 * HZ); + spin_lock(&state->lock); + } + finish_wait(&state->wq, &waiter); + + if (state->status != TPM_USER_CANCELLED) + state->status = TPM_USER_EIO; + else + state->status = TPM_USER_IDLE; + } + + spin_unlock(&state->lock); +} + +/* + * Allow the TPM emulator to wait for a request + */ +static unsigned int tpm_user_poll(struct file *file, + struct poll_table_struct *poll) +{ + struct tpm_user_state *state = file->private_data; + enum tpm_user_status status = ACCESS_ONCE(state->status); + unsigned mask; + + poll_wait(file, &state->wq, poll); + mask = 0; + + switch (status) { + case TPM_USER_SENDING: + return POLLIN; + case TPM_USER_AWAITING_REPLY: + return POLLOUT; + case TPM_USER_CANCELLING: + return POLLPRI; + case TPM_USER_EIO: + return POLLERR; + default: + return 0; + } +} + +static const struct tpm_class_ops tpm_user_class = { + .status = tpm_user_status, + .recv = tpm_user_recv, + .send = tpm_user_send, + .cancel = tpm_user_cancel, + .req_complete_mask = 1, + .req_complete_val = 1, + .req_canceled = tpm_user_is_req_cancelled, +}; + +/* + * Asynchronous initialiser. We have to do it this way because we get timeouts + * and run a selftest on the TPM - which means doing reads and writes on the + * file. + */ +static void tpm_user_initialiser(struct work_struct *work) +{ + struct tpm_user_state *state = + container_of(work, struct tpm_user_state, initialiser_work); + struct platform_device *pdev; + struct tpm_chip *chip; + int ret = -ENODEV; + + kenter(""); + + pdev = platform_device_register_simple("tpm_user", -1, NULL, 0); + if (IS_ERR(pdev)) { + ret = PTR_ERR(pdev); + goto err_dev; + } + state->pdev = pdev; + + pr_devel("Registering TPM\n"); + + ret = -ENODEV; + chip = tpm_register_hardware(&pdev->dev, &tpm_user_class); + if (!chip) + goto err_reg; + + chip->vendor.priv = state; + init_waitqueue_head(&chip->vendor.read_queue); + init_waitqueue_head(&chip->vendor.int_queue); + INIT_LIST_HEAD(&chip->vendor.list); + state->chip = chip; + + /* Default timeouts */ + chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); + chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT); + chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT); + chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); + + /* We will need to operate the communication channel */ + spin_lock(&state->lock); + ret = -EIO; + if (state->status == TPM_USER_EIO) + goto err_tpm_locked; + state->status = TPM_USER_IDLE; + spin_unlock(&state->lock); + + /* Not all variants of the emulator support getting the timeout */ + pr_devel("Getting timeouts\n"); + if (tpm_get_timeouts(chip)) + dev_err(&pdev->dev, "Could not get TPM timeouts and durations\n"); + + pr_devel("Performing selftest\n"); + ret = tpm_do_selftest(chip); + if (ret < 0) { + dev_err(&pdev->dev, "TPM self test failed\n"); + goto err_tpm; + } + + ret = 0; +out: + state->initialiser_error = ret; + kleave(" = %d", ret); + complete(&state->initialiser_done); + return; + +err_tpm: + spin_lock(&state->lock); + if (state->status != TPM_USER_EIO) + state->status = TPM_USER_EIO; +err_tpm_locked: + spin_unlock(&state->lock); + wake_up(&state->wq); + tpm_remove_hardware(chip->dev); +err_reg: + platform_device_unregister(pdev); +err_dev: + goto out; +} + +/* + * Allow the TPM emulator to create a virtual TPM. + */ +static int tpm_user_open(struct inode *inode, struct file *file) +{ + struct tpm_user_state *state; + + kenter(""); + + state = kzalloc(sizeof(struct tpm_user_state), GFP_KERNEL); + if (!state) + return -ENOMEM; + state->file = file; + state->status = TPM_USER_INITIALISING; + spin_lock_init(&state->lock); + INIT_WORK(&state->initialiser_work, tpm_user_initialiser); + init_completion(&state->initialiser_done); + init_waitqueue_head(&state->wq); + + file->private_data = state; + + /* The TPM registration must be done in another thread because the the + * process will involve self-testing the TPM and will thus need to + * communicate through this file. + */ + schedule_work(&state->initialiser_work); + kleave(" = 0"); + return 0; +} + +/* + * Release and clean up a virtual TPM. + */ +static int tpm_user_release(struct inode *inode, struct file *file) +{ + struct tpm_user_state *state = file->private_data; + int ret; + + kenter(""); + + pr_devel("forcing EIO state\n"); + spin_lock(&state->lock); + state->status = TPM_USER_EIO; + spin_unlock(&state->lock); + wake_up(&state->wq); + + wait_for_completion(&state->initialiser_done); + + ret = state->initialiser_error; + if (ret == 0) { + pr_devel("removing bits\n"); + tpm_remove_hardware(state->chip->dev); + platform_device_unregister(state->pdev); + } + kfree(state->to_emulator_q); + kfree(state->from_emulator_q); + kfree(state); + kleave(" = %d", ret); + return ret; +} + +static const struct file_operations tpm_user_fops = { + .owner = THIS_MODULE, + .open = tpm_user_open, + .release = tpm_user_release, + .read = tpm_user_read, + .write = tpm_user_write, + .unlocked_ioctl = tpm_user_ioctl, + .poll = tpm_user_poll, + .llseek = noop_llseek, +}; + +static struct miscdevice tpm_user_dev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "tpm_emul", + .fops = &tpm_user_fops, +}; + +/* + * Initialise a device + */ +static __init int tpm_user_mod_init(void) +{ + return misc_register(&tpm_user_dev); +} +device_initcall(tpm_user_mod_init); + +static __exit void tpm_user_mod_exit(void) +{ + misc_deregister(&tpm_user_dev); +} +module_exit(tpm_user_mod_exit); diff --git a/include/linux/wait.h b/include/linux/wait.h index bd68819f0815..8b443229997e 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h @@ -294,6 +294,10 @@ do { \ (void)___wait_event(wq, condition, TASK_UNINTERRUPTIBLE, 0, 0, \ cmd1; schedule(); cmd2) +#define __wait_event_cmd_interruptible(wq, condition, cmd1, cmd2) \ + (void)___wait_event(wq, condition, TASK_INTERRUPTIBLE, 0, 0, \ + cmd1; schedule(); cmd2) + /** * wait_event_cmd - sleep until a condition gets true * @wq: the waitqueue to wait on @@ -315,6 +319,13 @@ do { \ __wait_event_cmd(wq, condition, cmd1, cmd2); \ } while (0) +#define wait_event_cmd_interruptible(wq, condition, cmd1, cmd2) \ +do { \ + if (condition) \ + break; \ + __wait_event_cmd_interruptible(wq, condition, cmd1, cmd2); \ +} while (0) + #define __wait_event_interruptible(wq, condition) \ ___wait_event(wq, condition, TASK_INTERRUPTIBLE, 0, 0, \ schedule()) From patchwork Tue Aug 21 15:57:09 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 10571925 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 298A21390 for ; Tue, 21 Aug 2018 15:57:14 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 18ADE2A966 for ; Tue, 21 Aug 2018 15:57:14 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0CA132A97A; Tue, 21 Aug 2018 15:57:14 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 05C212A966 for ; Tue, 21 Aug 2018 15:57:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728082AbeHUTRx (ORCPT ); Tue, 21 Aug 2018 15:17:53 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:45102 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726967AbeHUTRx (ORCPT ); Tue, 21 Aug 2018 15:17:53 -0400 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 364EA402178A; Tue, 21 Aug 2018 15:57:11 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-123-147.rdu2.redhat.com [10.10.123.147]) by smtp.corp.redhat.com (Postfix) with ESMTP id 447D77D4DC; Tue, 21 Aug 2018 15:57:10 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 03/23] TPM: Provide a platform driver for the user emulator driver From: David Howells To: denkenz@gmail.com, jarkko.sakkinen@linux.intel.com, jejb@linux.vnet.ibm.com Cc: keyrings@vger.kernel.org, linux-integrity@vger.kernel.org, tpmdd-devel@lists.sourceforge.net, linux-security-module@vger.kernel.org Date: Tue, 21 Aug 2018 16:57:09 +0100 Message-ID: <153486702979.13066.16900998092976336647.stgit@warthog.procyon.org.uk> In-Reply-To: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> References: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Tue, 21 Aug 2018 15:57:11 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Tue, 21 Aug 2018 15:57:11 +0000 (UTC) for IP:'10.11.54.5' DOMAIN:'int-mx05.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'dhowells@redhat.com' RCPT:'' Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Provide a platform driver for the user emulator driver. This seems to be necessary to stop tpm_chip_find_get() from blowing up because it assumes unconditionally that any device will have a driver attached: if (try_module_get(pos->dev->driver->owner)) { However, this doesn't then work right because if I remove the TPM device and re-add it, the tpm ID isn't recycled (ie, /dev/tpm0 becomes unavailable and the new TPM is /dev/tpm1). Signed-off-by: David Howells --- drivers/char/tpm/tpm_user_emul.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/char/tpm/tpm_user_emul.c b/drivers/char/tpm/tpm_user_emul.c index b96350592bca..e5b13358c71e 100644 --- a/drivers/char/tpm/tpm_user_emul.c +++ b/drivers/char/tpm/tpm_user_emul.c @@ -656,17 +656,39 @@ static struct miscdevice tpm_user_dev = { .fops = &tpm_user_fops, }; +static struct platform_driver tpm_user_drv = { + .driver = { + .name = "tpm_user", + .owner = THIS_MODULE, + /* .pm = &tpm_user_pm, -- do we need pm since there's no h/w? */ + }, +}; + /* * Initialise a device */ static __init int tpm_user_mod_init(void) { - return misc_register(&tpm_user_dev); + int ret; + + ret = platform_driver_register(&tpm_user_drv); + if (ret < 0) + return ret; + + ret = misc_register(&tpm_user_dev); + if (ret < 0) + goto error_dev; + return 0; + +error_dev: + platform_driver_unregister(&tpm_user_drv); + return ret; } device_initcall(tpm_user_mod_init); static __exit void tpm_user_mod_exit(void) { misc_deregister(&tpm_user_dev); + platform_driver_unregister(&tpm_user_drv); } module_exit(tpm_user_mod_exit); From patchwork Tue Aug 21 15:57:16 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 10571929 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 91C0E17E0 for ; Tue, 21 Aug 2018 15:57:20 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 80EEA2A7D1 for ; Tue, 21 Aug 2018 15:57:20 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 74B7F2A9A8; Tue, 21 Aug 2018 15:57:20 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 24CC82A7D1 for ; Tue, 21 Aug 2018 15:57:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728086AbeHUTSB (ORCPT ); Tue, 21 Aug 2018 15:18:01 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:44744 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1728085AbeHUTSB (ORCPT ); Tue, 21 Aug 2018 15:18:01 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id C6C8787A82; Tue, 21 Aug 2018 15:57:17 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-123-147.rdu2.redhat.com [10.10.123.147]) by smtp.corp.redhat.com (Postfix) with ESMTP id CFB202156889; Tue, 21 Aug 2018 15:57:16 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 04/23] TPM: Expose struct tpm_chip and related find_get and put functions From: David Howells To: denkenz@gmail.com, jarkko.sakkinen@linux.intel.com, jejb@linux.vnet.ibm.com Cc: keyrings@vger.kernel.org, linux-integrity@vger.kernel.org, tpmdd-devel@lists.sourceforge.net, linux-security-module@vger.kernel.org Date: Tue, 21 Aug 2018 16:57:16 +0100 Message-ID: <153486703636.13066.16209594327379341518.stgit@warthog.procyon.org.uk> In-Reply-To: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> References: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 21 Aug 2018 15:57:17 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 21 Aug 2018 15:57:17 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'dhowells@redhat.com' RCPT:'' Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Expose struct tpm_chip and related find_get and put functions so that TPM-using code can make sure it uses the same TPM for any related set of operations. Signed-off-by: David Howells --- drivers/char/tpm/tpm-interface.c | 19 ++++++++++++++++--- drivers/char/tpm/tpm.h | 5 ----- include/linux/tpm.h | 10 ++++++++++ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index cfb9089887bd..b8f1df5b64fe 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -636,10 +636,11 @@ static int tpm_continue_selftest(struct tpm_chip *chip) return rc; } -/* - * tpm_chip_find_get - return tpm_chip for given chip number +/** + * tpm_chip_find_get - Look up a TPM chip by device index + * @chip_num: The index number of the chip to use or TPM_ANY_NUM */ -static struct tpm_chip *tpm_chip_find_get(int chip_num) +struct tpm_chip *tpm_chip_find_get(int chip_num) { struct tpm_chip *pos, *chip = NULL; @@ -656,6 +657,18 @@ static struct tpm_chip *tpm_chip_find_get(int chip_num) rcu_read_unlock(); return chip; } +EXPORT_SYMBOL_GPL(tpm_chip_find_get); + +/** + * tpm_chip_put - Release a previously looked up TPM chip + * @chip: The chip to release + */ +void tpm_chip_put(struct tpm_chip *chip) +{ + if (chip) + module_put(chip->dev->driver->owner); +} +EXPORT_SYMBOL_GPL(tpm_chip_put); #define TPM_ORDINAL_PCRREAD cpu_to_be32(21) #define READ_PCR_RESULT_SIZE 30 diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index e4d0888d2eab..df6ffceb3429 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -115,11 +115,6 @@ struct tpm_chip { #define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor) -static inline void tpm_chip_put(struct tpm_chip *chip) -{ - module_put(chip->dev->driver->owner); -} - static inline int tpm_read_index(int base, int index) { outb(index, base); diff --git a/include/linux/tpm.h b/include/linux/tpm.h index 8350c538b486..44c8cad7132d 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -46,11 +46,21 @@ struct tpm_class_ops { #if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE) +extern struct tpm_chip *tpm_chip_find_get(int chip_num); +extern void tpm_chip_put(struct tpm_chip *chip); + extern int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf); extern int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash); extern int tpm_send(u32 chip_num, void *cmd, size_t buflen); extern int tpm_get_random(u32 chip_num, u8 *data, size_t max); #else +static inline struct tpm_chip *tpm_chip_find_get(int chip_num) +{ + return NULL; +} +static inline void tpm_chip_put(struct tpm_chip *chip) +{ +} static inline int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) { return -ENODEV; } From patchwork Tue Aug 21 15:57:22 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 10571933 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8E5DE17E0 for ; Tue, 21 Aug 2018 15:57:30 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 79A4B2A7D1 for ; Tue, 21 Aug 2018 15:57:30 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6DBDF2A9AA; Tue, 21 Aug 2018 15:57:30 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4A3082A976 for ; Tue, 21 Aug 2018 15:57:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727043AbeHUTSK (ORCPT ); Tue, 21 Aug 2018 15:18:10 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:44754 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726967AbeHUTSK (ORCPT ); Tue, 21 Aug 2018 15:18:10 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 9615C83221; Tue, 21 Aug 2018 15:57:24 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-123-147.rdu2.redhat.com [10.10.123.147]) by smtp.corp.redhat.com (Postfix) with ESMTP id 6B1CE1010413; Tue, 21 Aug 2018 15:57:23 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 05/23] TPM: Use struct tpm_chip rather than chip number as interface parameter From: David Howells To: denkenz@gmail.com, jarkko.sakkinen@linux.intel.com, jejb@linux.vnet.ibm.com Cc: keyrings@vger.kernel.org, linux-integrity@vger.kernel.org, tpmdd-devel@lists.sourceforge.net, linux-security-module@vger.kernel.org Date: Tue, 21 Aug 2018 16:57:22 +0100 Message-ID: <153486704294.13066.8818198038331415342.stgit@warthog.procyon.org.uk> In-Reply-To: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> References: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 21 Aug 2018 15:57:24 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 21 Aug 2018 15:57:24 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'dhowells@redhat.com' RCPT:'' Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Use struct tpm_chip rather than chip number as interface parameter for most interface functions. This allows the client to be sure about the consistency of what device it uses. Signed-off-by: David Howells --- drivers/char/tpm/tpm-interface.c | 76 ++++++++------------------------- drivers/char/tpm/tpm-sysfs.c | 2 - include/linux/tpm.h | 16 ++++--- security/integrity/ima/ima.h | 2 - security/integrity/ima/ima_crypto.c | 4 +- security/integrity/ima/ima_init.c | 19 +++++--- security/integrity/ima/ima_queue.c | 4 +- security/keys/trusted.c | 80 ++++++++++++++++++++++------------- 8 files changed, 96 insertions(+), 107 deletions(-) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index b8f1df5b64fe..29c2ce5cfc69 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -678,25 +678,9 @@ static struct tpm_input_header pcrread_header = { .ordinal = TPM_ORDINAL_PCRREAD }; -int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) -{ - int rc; - struct tpm_cmd_t cmd; - - cmd.header.in = pcrread_header; - cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx); - rc = transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE, - "attempting to read a pcr value"); - - if (rc == 0) - memcpy(res_buf, cmd.params.pcrread_out.pcr_result, - TPM_DIGEST_SIZE); - return rc; -} - /** * tpm_pcr_read - read a pcr value - * @chip_num: tpm idx # or ANY + * @chip: The chip to pass the request to * @pcr_idx: pcr idx to retrieve * @res_buf: TPM_PCR value * size of res_buf is 20 bytes (or NULL if you don't care) @@ -705,23 +689,26 @@ int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) * isn't, protect against the chip disappearing, by incrementing * the module usage count. */ -int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) +int tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) { - struct tpm_chip *chip; int rc; + struct tpm_cmd_t cmd; - chip = tpm_chip_find_get(chip_num); - if (chip == NULL) - return -ENODEV; - rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf); - tpm_chip_put(chip); + cmd.header.in = pcrread_header; + cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx); + rc = transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE, + "attempting to read a pcr value"); + + if (rc == 0) + memcpy(res_buf, cmd.params.pcrread_out.pcr_result, + TPM_DIGEST_SIZE); return rc; } EXPORT_SYMBOL_GPL(tpm_pcr_read); /** * tpm_pcr_extend - extend pcr value with hash - * @chip_num: tpm idx # or AN& + * @chip: The chip to pass the request to * @pcr_idx: pcr idx to extend * @hash: hash value used to extend pcr value * @@ -737,24 +724,15 @@ static struct tpm_input_header pcrextend_header = { .ordinal = TPM_ORD_PCR_EXTEND }; -int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) +int tpm_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash) { struct tpm_cmd_t cmd; - int rc; - struct tpm_chip *chip; - - chip = tpm_chip_find_get(chip_num); - if (chip == NULL) - return -ENODEV; cmd.header.in = pcrextend_header; cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx); memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE); - rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, - "attempting extend a PCR value"); - - tpm_chip_put(chip); - return rc; + return transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, + "attempting extend a PCR value"); } EXPORT_SYMBOL_GPL(tpm_pcr_extend); @@ -821,19 +799,9 @@ int tpm_do_selftest(struct tpm_chip *chip) } EXPORT_SYMBOL_GPL(tpm_do_selftest); -int tpm_send(u32 chip_num, void *cmd, size_t buflen) +int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen) { - struct tpm_chip *chip; - int rc; - - chip = tpm_chip_find_get(chip_num); - if (chip == NULL) - return -ENODEV; - - rc = transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd"); - - tpm_chip_put(chip); - return rc; + return transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd"); } EXPORT_SYMBOL_GPL(tpm_send); @@ -1010,15 +978,14 @@ static struct tpm_input_header tpm_getrandom_header = { /** * tpm_get_random() - Get random bytes from the tpm's RNG - * @chip_num: A specific chip number for the request or TPM_ANY_NUM + * @chip: The chip to pass the request to * @out: destination buffer for the random bytes * @max: the max number of bytes to write to @out * * Returns < 0 on error and the number of bytes read on success */ -int tpm_get_random(u32 chip_num, u8 *out, size_t max) +int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max) { - struct tpm_chip *chip; struct tpm_cmd_t tpm_cmd; u32 recd, num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA); int err, total = 0, retries = 5; @@ -1027,10 +994,6 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) if (!out || !num_bytes || max > TPM_MAX_RNG_DATA) return -EINVAL; - chip = tpm_chip_find_get(chip_num); - if (chip == NULL) - return -ENODEV; - do { tpm_cmd.header.in = tpm_getrandom_header; tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes); @@ -1049,7 +1012,6 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) num_bytes -= recd; } while (retries-- && total < max); - tpm_chip_put(chip); return total ? total : -EIO; } EXPORT_SYMBOL_GPL(tpm_get_random); diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c index 01730a27ae07..507d8ab37ef1 100644 --- a/drivers/char/tpm/tpm-sysfs.c +++ b/drivers/char/tpm/tpm-sysfs.c @@ -120,7 +120,7 @@ static ssize_t pcrs_show(struct device *dev, struct device_attribute *attr, num_pcrs = be32_to_cpu(cap.num_pcrs); for (i = 0; i < num_pcrs; i++) { - rc = tpm_pcr_read_dev(chip, i, digest); + rc = tpm_pcr_read(chip, i, digest); if (rc) break; str += sprintf(str, "PCR-%02d: ", i); diff --git a/include/linux/tpm.h b/include/linux/tpm.h index 44c8cad7132d..c213e09b7d81 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -49,10 +49,10 @@ struct tpm_class_ops { extern struct tpm_chip *tpm_chip_find_get(int chip_num); extern void tpm_chip_put(struct tpm_chip *chip); -extern int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf); -extern int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash); -extern int tpm_send(u32 chip_num, void *cmd, size_t buflen); -extern int tpm_get_random(u32 chip_num, u8 *data, size_t max); +extern int tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf); +extern int tpm_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash); +extern int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen); +extern int tpm_get_random(struct tpm_chip *chip, u8 *data, size_t max); #else static inline struct tpm_chip *tpm_chip_find_get(int chip_num) { @@ -61,16 +61,16 @@ static inline struct tpm_chip *tpm_chip_find_get(int chip_num) static inline void tpm_chip_put(struct tpm_chip *chip) { } -static inline int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) { +static inline int tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) { return -ENODEV; } -static inline int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) { +static inline int tpm_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash) { return -ENODEV; } -static inline int tpm_send(u32 chip_num, void *cmd, size_t buflen) { +static inline int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen) { return -ENODEV; } -static inline int tpm_get_random(u32 chip_num, u8 *data, size_t max) { +static inline int tpm_get_random(struct tpm_chip *chip, u8 *data, size_t max) { return -ENODEV; } #endif diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 8e4bb883fc13..8f932e53a449 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -44,8 +44,8 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 }; #define IMA_TEMPLATE_IMA_FMT "d|n" /* set during initialization */ +extern struct tpm_chip *ima_tpm; extern int ima_initialized; -extern int ima_used_chip; extern int ima_hash_algo; extern int ima_appraise; diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index d34e7dfc1118..c4631e5bac5a 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c @@ -556,10 +556,10 @@ int ima_calc_field_array_hash(struct ima_field_data *field_data, static void __init ima_pcrread(int idx, u8 *pcr) { - if (!ima_used_chip) + if (!ima_tpm) return; - if (tpm_pcr_read(TPM_ANY_NUM, idx, pcr) != 0) + if (tpm_pcr_read(ima_tpm, idx, pcr) != 0) pr_err("Error Communicating to TPM chip\n"); } diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index e8f9d70a465d..bcad4da9e663 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c @@ -26,7 +26,7 @@ /* name for boot aggregate entry */ static const char *boot_aggregate_name = "boot_aggregate"; -int ima_used_chip; +struct tpm_chip *ima_tpm; /* Add the boot aggregate to the IMA measurement list and extend * the PCR register. @@ -62,7 +62,7 @@ static void __init ima_add_boot_aggregate(void) iint->ima_hash->algo = HASH_ALGO_SHA1; iint->ima_hash->length = SHA1_DIGEST_SIZE; - if (ima_used_chip) { + if (ima_tpm) { result = ima_calc_boot_aggregate(&hash.hdr); if (result < 0) { audit_cause = "hashing_error"; @@ -90,12 +90,17 @@ int __init ima_init(void) u8 pcr_i[TPM_DIGEST_SIZE]; int rc; - ima_used_chip = 0; - rc = tpm_pcr_read(TPM_ANY_NUM, 0, pcr_i); - if (rc == 0) - ima_used_chip = 1; + ima_tpm = tpm_chip_find_get(TPM_ANY_NUM); - if (!ima_used_chip) + if (ima_tpm) { + rc = tpm_pcr_read(ima_tpm, 0, pcr_i); + if (rc != 0) { + tpm_chip_put(ima_tpm); + ima_tpm = NULL; + } + } + + if (!ima_tpm) pr_info("No TPM chip found, activating TPM-bypass!\n"); rc = ima_init_crypto(); diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c index 552705d5a78d..83629075375c 100644 --- a/security/integrity/ima/ima_queue.c +++ b/security/integrity/ima/ima_queue.c @@ -93,10 +93,10 @@ static int ima_pcr_extend(const u8 *hash) { int result = 0; - if (!ima_used_chip) + if (!ima_tpm) return result; - result = tpm_pcr_extend(TPM_ANY_NUM, CONFIG_IMA_MEASURE_PCR_IDX, hash); + result = tpm_pcr_extend(ima_tpm, CONFIG_IMA_MEASURE_PCR_IDX, hash); if (result != 0) pr_err("Error Communicating to TPM chip, result: %d\n", result); return result; diff --git a/security/keys/trusted.c b/security/keys/trusted.c index c0594cb07ada..adb0caa5c38d 100644 --- a/security/keys/trusted.c +++ b/security/keys/trusted.c @@ -354,13 +354,13 @@ out: * For key specific tpm requests, we will generate and send our * own TPM command packets using the drivers send function. */ -static int trusted_tpm_send(const u32 chip_num, unsigned char *cmd, +static int trusted_tpm_send(struct tpm_chip *chip, unsigned char *cmd, size_t buflen) { int rc; dump_tpm_buf(cmd); - rc = tpm_send(chip_num, cmd, buflen); + rc = tpm_send(chip, cmd, buflen); dump_tpm_buf(cmd); if (rc > 0) /* Can't return positive return codes values to keyctl */ @@ -374,30 +374,31 @@ static int trusted_tpm_send(const u32 chip_num, unsigned char *cmd, * Prevents a trusted key that is sealed to PCRs from being accessed. * This uses the tpm driver's extend function. */ -static int pcrlock(const int pcrnum) +static int pcrlock(struct tpm_chip *chip, const int pcrnum) { unsigned char hash[SHA1_DIGEST_SIZE]; int ret; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - ret = tpm_get_random(TPM_ANY_NUM, hash, SHA1_DIGEST_SIZE); + ret = tpm_get_random(chip, hash, SHA1_DIGEST_SIZE); if (ret != SHA1_DIGEST_SIZE) return ret; - return tpm_pcr_extend(TPM_ANY_NUM, pcrnum, hash) ? -EINVAL : 0; + return tpm_pcr_extend(chip, pcrnum, hash) ? -EINVAL : 0; } /* * Create an object specific authorisation protocol (OSAP) session */ -static int osap(struct tpm_buf *tb, struct osapsess *s, +static int osap(struct tpm_chip *chip, + struct tpm_buf *tb, struct osapsess *s, const unsigned char *key, uint16_t type, uint32_t handle) { unsigned char enonce[TPM_NONCE_SIZE]; unsigned char ononce[TPM_NONCE_SIZE]; int ret; - ret = tpm_get_random(TPM_ANY_NUM, ononce, TPM_NONCE_SIZE); + ret = tpm_get_random(chip, ononce, TPM_NONCE_SIZE); if (ret != TPM_NONCE_SIZE) return ret; @@ -409,7 +410,7 @@ static int osap(struct tpm_buf *tb, struct osapsess *s, store32(tb, handle); storebytes(tb, ononce, TPM_NONCE_SIZE); - ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE); + ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE); if (ret < 0) return ret; @@ -425,7 +426,8 @@ static int osap(struct tpm_buf *tb, struct osapsess *s, /* * Create an object independent authorisation protocol (oiap) session */ -static int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce) +static int oiap(struct tpm_chip *chip, struct tpm_buf *tb, uint32_t *handle, + unsigned char *nonce) { int ret; @@ -433,7 +435,7 @@ static int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce) store16(tb, TPM_TAG_RQU_COMMAND); store32(tb, TPM_OIAP_SIZE); store32(tb, TPM_ORD_OIAP); - ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE); + ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE); if (ret < 0) return ret; @@ -455,7 +457,8 @@ struct tpm_digests { * Have the TPM seal(encrypt) the trusted key, possibly based on * Platform Configuration Registers (PCRs). AUTH1 for sealing key. */ -static int tpm_seal(struct tpm_buf *tb, uint16_t keytype, +static int tpm_seal(struct tpm_chip *chip, + struct tpm_buf *tb, uint16_t keytype, uint32_t keyhandle, const unsigned char *keyauth, const unsigned char *data, uint32_t datalen, unsigned char *blob, uint32_t *bloblen, @@ -480,7 +483,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype, return -ENOMEM; /* get session for sealing key */ - ret = osap(tb, &sess, keyauth, keytype, keyhandle); + ret = osap(chip, tb, &sess, keyauth, keytype, keyhandle); if (ret < 0) goto out; dump_sess(&sess); @@ -492,7 +495,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype, if (ret < 0) goto out; - ret = tpm_get_random(TPM_ANY_NUM, td->nonceodd, TPM_NONCE_SIZE); + ret = tpm_get_random(chip, td->nonceodd, TPM_NONCE_SIZE); if (ret != TPM_NONCE_SIZE) goto out; ordinal = htonl(TPM_ORD_SEAL); @@ -541,7 +544,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype, store8(tb, cont); storebytes(tb, td->pubauth, SHA1_DIGEST_SIZE); - ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE); + ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE); if (ret < 0) goto out; @@ -570,7 +573,7 @@ out: /* * use the AUTH2_COMMAND form of unseal, to authorize both key and blob */ -static int tpm_unseal(struct tpm_buf *tb, +static int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, uint32_t keyhandle, const unsigned char *keyauth, const unsigned char *blob, int bloblen, const unsigned char *blobauth, @@ -589,12 +592,12 @@ static int tpm_unseal(struct tpm_buf *tb, int ret; /* sessions for unsealing key and data */ - ret = oiap(tb, &authhandle1, enonce1); + ret = oiap(chip, tb, &authhandle1, enonce1); if (ret < 0) { pr_info("trusted_key: oiap failed (%d)\n", ret); return ret; } - ret = oiap(tb, &authhandle2, enonce2); + ret = oiap(chip, tb, &authhandle2, enonce2); if (ret < 0) { pr_info("trusted_key: oiap failed (%d)\n", ret); return ret; @@ -602,7 +605,7 @@ static int tpm_unseal(struct tpm_buf *tb, ordinal = htonl(TPM_ORD_UNSEAL); keyhndl = htonl(SRKHANDLE); - ret = tpm_get_random(TPM_ANY_NUM, nonceodd, TPM_NONCE_SIZE); + ret = tpm_get_random(chip, nonceodd, TPM_NONCE_SIZE); if (ret != TPM_NONCE_SIZE) { pr_info("trusted_key: tpm_get_random failed (%d)\n", ret); return ret; @@ -634,7 +637,7 @@ static int tpm_unseal(struct tpm_buf *tb, store8(tb, cont); storebytes(tb, authdata2, SHA1_DIGEST_SIZE); - ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE); + ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE); if (ret < 0) { pr_info("trusted_key: authhmac failed (%d)\n", ret); return ret; @@ -658,7 +661,8 @@ static int tpm_unseal(struct tpm_buf *tb, /* * Have the TPM seal(encrypt) the symmetric key */ -static int key_seal(struct trusted_key_payload *p, +static int key_seal(struct tpm_chip *chip, + struct trusted_key_payload *p, struct trusted_key_options *o) { struct tpm_buf *tb; @@ -671,7 +675,7 @@ 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, + ret = tpm_seal(chip, tb, o->keytype, o->keyhandle, o->keyauth, p->key, p->key_len + 1, p->blob, &p->blob_len, o->blobauth, o->pcrinfo, o->pcrinfo_len); if (ret < 0) @@ -684,7 +688,8 @@ static int key_seal(struct trusted_key_payload *p, /* * Have the TPM unseal(decrypt) the symmetric key */ -static int key_unseal(struct trusted_key_payload *p, +static int key_unseal(struct tpm_chip *chip, + struct trusted_key_payload *p, struct trusted_key_options *o) { struct tpm_buf *tb; @@ -694,7 +699,8 @@ static int key_unseal(struct trusted_key_payload *p, if (!tb) return -ENOMEM; - ret = tpm_unseal(tb, o->keyhandle, o->keyauth, p->blob, p->blob_len, + ret = tpm_unseal(chip, tb, o->keyhandle, o->keyauth, + p->blob, p->blob_len, o->blobauth, p->key, &p->key_len); if (ret < 0) pr_info("trusted_key: srkunseal failed (%d)\n", ret); @@ -900,6 +906,7 @@ static int trusted_instantiate(struct key *key, { struct trusted_key_payload *payload = NULL; struct trusted_key_options *options = NULL; + struct tpm_chip *chip = NULL; size_t datalen = prep->datalen; char *datablob; int ret = 0; @@ -935,9 +942,14 @@ static int trusted_instantiate(struct key *key, dump_payload(payload); dump_options(options); + ret = -ENODEV; + chip = tpm_chip_find_get(TPM_ANY_NUM); + if (!chip) + goto out; + switch (key_cmd) { case Opt_load: - ret = key_unseal(payload, options); + ret = key_unseal(chip, payload, options); dump_payload(payload); dump_options(options); if (ret < 0) @@ -945,12 +957,12 @@ static int trusted_instantiate(struct key *key, break; case Opt_new: key_len = payload->key_len; - ret = tpm_get_random(TPM_ANY_NUM, payload->key, key_len); + ret = tpm_get_random(chip, payload->key, key_len); if (ret != key_len) { pr_info("trusted_key: key_create failed (%d)\n", ret); goto out; } - ret = key_seal(payload, options); + ret = key_seal(chip, payload, options); if (ret < 0) pr_info("trusted_key: key_seal failed (%d)\n", ret); break; @@ -958,9 +970,11 @@ static int trusted_instantiate(struct key *key, ret = -EINVAL; goto out; } + if (!ret && options->pcrlock) - ret = pcrlock(options->pcrlock); + ret = pcrlock(chip, options->pcrlock); out: + tpm_chip_put(chip); kfree(datablob); kfree(options); if (!ret) @@ -987,6 +1001,7 @@ static int trusted_update(struct key *key, struct key_preparsed_payload *prep) struct trusted_key_payload *p = key->payload.data; struct trusted_key_payload *new_p; struct trusted_key_options *new_o; + struct tpm_chip *chip = NULL; size_t datalen = prep->datalen; char *datablob; int ret = 0; @@ -1018,6 +1033,7 @@ static int trusted_update(struct key *key, struct key_preparsed_payload *prep) kfree(new_p); goto out; } + /* copy old key values, and reseal with new pcrs */ new_p->migratable = p->migratable; new_p->key_len = p->key_len; @@ -1025,14 +1041,19 @@ static int trusted_update(struct key *key, struct key_preparsed_payload *prep) dump_payload(p); dump_payload(new_p); - ret = key_seal(new_p, new_o); + ret = -ENODEV; + chip = tpm_chip_find_get(TPM_ANY_NUM); + if (!chip) + goto out; + + ret = key_seal(chip, new_p, new_o); if (ret < 0) { pr_info("trusted_key: key_seal failed (%d)\n", ret); kfree(new_p); goto out; } if (new_o->pcrlock) { - ret = pcrlock(new_o->pcrlock); + ret = pcrlock(chip, new_o->pcrlock); if (ret < 0) { pr_info("trusted_key: pcrlock failed (%d)\n", ret); kfree(new_p); @@ -1042,6 +1063,7 @@ static int trusted_update(struct key *key, struct key_preparsed_payload *prep) rcu_assign_keypointer(key, new_p); call_rcu(&p->rcu, trusted_rcu_free); out: + tpm_chip_put(chip); kfree(datablob); kfree(new_o); return ret; From patchwork Tue Aug 21 15:57:29 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 10571935 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4F61D1390 for ; Tue, 21 Aug 2018 15:57:34 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3B5702A976 for ; Tue, 21 Aug 2018 15:57:34 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2FB822A994; Tue, 21 Aug 2018 15:57:34 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A4DA82A976 for ; Tue, 21 Aug 2018 15:57:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728096AbeHUTSO (ORCPT ); Tue, 21 Aug 2018 15:18:14 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:43454 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726967AbeHUTSO (ORCPT ); Tue, 21 Aug 2018 15:18:14 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 4915740216E8; Tue, 21 Aug 2018 15:57:31 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-123-147.rdu2.redhat.com [10.10.123.147]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3E2FD2026D64; Tue, 21 Aug 2018 15:57:30 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 06/23] TPM: Move ordinal values from interface file to header with other ordinals From: David Howells To: denkenz@gmail.com, jarkko.sakkinen@linux.intel.com, jejb@linux.vnet.ibm.com Cc: keyrings@vger.kernel.org, linux-integrity@vger.kernel.org, tpmdd-devel@lists.sourceforge.net, linux-security-module@vger.kernel.org Date: Tue, 21 Aug 2018 16:57:29 +0100 Message-ID: <153486704975.13066.1880897540173112691.stgit@warthog.procyon.org.uk> In-Reply-To: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> References: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Tue, 21 Aug 2018 15:57:31 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Tue, 21 Aug 2018 15:57:31 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'dhowells@redhat.com' RCPT:'' Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Move the ordinal values (command IDs) from the tpm-interface.c file to the tpm_command.h header where the other ordinal values are declared. Use cpu_to_be32() when the ordinal values are used, and not in their declarations. The TPM_TAG_RQU_COMMAND definition in the internal tpm.h has to be removed because it is a differently-defined duplicate label to avoid a clash. cpu_to_be16() is then used in the places where it was used. This allows the infineon TPM driver to use the constants directly in tpm_inf_pnp_suspend(). The savestate buffer there can also be made static and const. Signed-off-by: David Howells --- drivers/char/tpm/tpm-interface.c | 48 +++++++++++++++++--------------------- drivers/char/tpm/tpm-sysfs.c | 8 +++--- drivers/char/tpm/tpm.h | 2 -- drivers/char/tpm/tpm_infineon.c | 6 ++--- include/linux/tpm_command.h | 19 +++++++++++---- 5 files changed, 42 insertions(+), 41 deletions(-) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 29c2ce5cfc69..9add6034c252 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "tpm.h" #include "tpm_eventlog.h" @@ -417,13 +418,11 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, } #define TPM_INTERNAL_RESULT_SIZE 200 -#define TPM_ORD_GET_CAP cpu_to_be32(101) -#define TPM_ORD_GET_RANDOM cpu_to_be32(70) static const struct tpm_input_header tpm_getcap_header = { - .tag = TPM_TAG_RQU_COMMAND, - .length = cpu_to_be32(22), - .ordinal = TPM_ORD_GET_CAP + .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND), + .length = cpu_to_be32(22), + .ordinal = cpu_to_be32(TPM_ORD_GET_CAP), }; ssize_t tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap, @@ -469,14 +468,13 @@ void tpm_gen_interrupt(struct tpm_chip *chip) } EXPORT_SYMBOL_GPL(tpm_gen_interrupt); -#define TPM_ORD_STARTUP cpu_to_be32(153) #define TPM_ST_CLEAR cpu_to_be16(1) #define TPM_ST_STATE cpu_to_be16(2) #define TPM_ST_DEACTIVATED cpu_to_be16(3) static const struct tpm_input_header tpm_startup_header = { - .tag = TPM_TAG_RQU_COMMAND, - .length = cpu_to_be32(12), - .ordinal = TPM_ORD_STARTUP + .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND), + .length = cpu_to_be32(12), + .ordinal = cpu_to_be32(TPM_ORD_STARTUP), }; static int tpm_startup(struct tpm_chip *chip, __be16 startup_type) @@ -609,12 +607,11 @@ duration: } EXPORT_SYMBOL_GPL(tpm_get_timeouts); -#define TPM_ORD_CONTINUE_SELFTEST 83 #define CONTINUE_SELFTEST_RESULT_SIZE 10 static struct tpm_input_header continue_selftest_header = { - .tag = TPM_TAG_RQU_COMMAND, - .length = cpu_to_be32(10), + .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND), + .length = cpu_to_be32(10), .ordinal = cpu_to_be32(TPM_ORD_CONTINUE_SELFTEST), }; @@ -670,12 +667,11 @@ void tpm_chip_put(struct tpm_chip *chip) } EXPORT_SYMBOL_GPL(tpm_chip_put); -#define TPM_ORDINAL_PCRREAD cpu_to_be32(21) #define READ_PCR_RESULT_SIZE 30 static struct tpm_input_header pcrread_header = { - .tag = TPM_TAG_RQU_COMMAND, - .length = cpu_to_be32(14), - .ordinal = TPM_ORDINAL_PCRREAD + .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND), + .length = cpu_to_be32(14), + .ordinal = cpu_to_be32(TPM_ORD_PCR_READ), }; /** @@ -716,12 +712,11 @@ EXPORT_SYMBOL_GPL(tpm_pcr_read); * isn't, protect against the chip disappearing, by incrementing * the module usage count. */ -#define TPM_ORD_PCR_EXTEND cpu_to_be32(20) #define EXTEND_PCR_RESULT_SIZE 34 static struct tpm_input_header pcrextend_header = { - .tag = TPM_TAG_RQU_COMMAND, - .length = cpu_to_be32(34), - .ordinal = TPM_ORD_PCR_EXTEND + .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND), + .length = cpu_to_be32(34), + .ordinal = cpu_to_be32(TPM_ORD_PCR_EXTEND) }; int tpm_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash) @@ -889,13 +884,12 @@ void tpm_remove_hardware(struct device *dev) } EXPORT_SYMBOL_GPL(tpm_remove_hardware); -#define TPM_ORD_SAVESTATE cpu_to_be32(152) #define SAVESTATE_RESULT_SIZE 10 static struct tpm_input_header savestate_header = { - .tag = TPM_TAG_RQU_COMMAND, - .length = cpu_to_be32(10), - .ordinal = TPM_ORD_SAVESTATE + .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND), + .length = cpu_to_be32(10), + .ordinal = cpu_to_be32(TPM_ORD_SAVESTATE), }; /* @@ -971,9 +965,9 @@ EXPORT_SYMBOL_GPL(tpm_pm_resume); #define TPM_GETRANDOM_RESULT_SIZE 18 static struct tpm_input_header tpm_getrandom_header = { - .tag = TPM_TAG_RQU_COMMAND, - .length = cpu_to_be32(14), - .ordinal = TPM_ORD_GET_RANDOM + .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND), + .length = cpu_to_be32(14), + .ordinal = cpu_to_be32(TPM_ORD_GET_RANDOM), }; /** diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c index 507d8ab37ef1..d8da83a1d11c 100644 --- a/drivers/char/tpm/tpm-sysfs.c +++ b/drivers/char/tpm/tpm-sysfs.c @@ -18,6 +18,7 @@ * */ #include +#include #include "tpm.h" /* XXX for now this helper is duplicated in tpm-interface.c */ @@ -40,11 +41,10 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, } #define READ_PUBEK_RESULT_SIZE 314 -#define TPM_ORD_READPUBEK cpu_to_be32(124) static struct tpm_input_header tpm_readpubek_header = { - .tag = TPM_TAG_RQU_COMMAND, - .length = cpu_to_be32(30), - .ordinal = TPM_ORD_READPUBEK + .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND), + .length = cpu_to_be32(30), + .ordinal = cpu_to_be32(TPM_ORD_READPUBEK), }; static ssize_t pubek_show(struct device *dev, struct device_attribute *attr, char *buf) diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index df6ffceb3429..2a1be0ec2fbd 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -138,8 +138,6 @@ struct tpm_output_header { __be32 return_code; } __packed; -#define TPM_TAG_RQU_COMMAND cpu_to_be16(193) - struct stclear_flags_t { __be16 tag; u8 deactivated; diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c index dc0a2554034e..7daa3317e18d 100644 --- a/drivers/char/tpm/tpm_infineon.c +++ b/drivers/char/tpm/tpm_infineon.c @@ -591,10 +591,10 @@ static int tpm_inf_pnp_suspend(struct pnp_dev *dev, pm_message_t pm_state) struct tpm_chip *chip = pnp_get_drvdata(dev); int rc; if (chip) { - u8 savestate[] = { - 0, 193, /* TPM_TAG_RQU_COMMAND */ + static const u8 savestate[] = { + 0, TPM_TAG_RQU_COMMAND, 0, 0, 0, 10, /* blob length (in bytes) */ - 0, 0, 0, 152 /* TPM_ORD_SaveState */ + 0, 0, 0, TPM_ORD_SAVESTATE, }; dev_info(&dev->dev, "saving TPM state\n"); rc = tpm_inf_send(chip, savestate, sizeof(savestate)); diff --git a/include/linux/tpm_command.h b/include/linux/tpm_command.h index 727512e249b5..a3e0bb670e62 100644 --- a/include/linux/tpm_command.h +++ b/include/linux/tpm_command.h @@ -15,11 +15,20 @@ #define TPM_TAG_RSP_AUTH2_COMMAND 198 /* Command Ordinals */ -#define TPM_ORD_GETRANDOM 70 -#define TPM_ORD_OSAP 11 -#define TPM_ORD_OIAP 10 -#define TPM_ORD_SEAL 23 -#define TPM_ORD_UNSEAL 24 +enum tpm_ordinal { + TPM_ORD_OSAP = 11, + TPM_ORD_OIAP = 10, + TPM_ORD_PCR_EXTEND = 20, + TPM_ORD_PCR_READ = 21, + TPM_ORD_SEAL = 23, + TPM_ORD_UNSEAL = 24, + TPM_ORD_GET_RANDOM = 70, + TPM_ORD_CONTINUE_SELFTEST = 83, + TPM_ORD_GET_CAP = 101, + TPM_ORD_READPUBEK = 124, + TPM_ORD_SAVESTATE = 152, + TPM_ORD_STARTUP = 153, +}; /* Other constants */ #define SRKHANDLE 0x40000000 From patchwork Tue Aug 21 15:57:36 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 10571941 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id DA6AD17E0 for ; Tue, 21 Aug 2018 15:57:44 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C97152A97A for ; Tue, 21 Aug 2018 15:57:44 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id BD8CB2A9AB; Tue, 21 Aug 2018 15:57:44 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A97782A97A for ; Tue, 21 Aug 2018 15:57:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728098AbeHUTSY (ORCPT ); Tue, 21 Aug 2018 15:18:24 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:43466 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726967AbeHUTSY (ORCPT ); Tue, 21 Aug 2018 15:18:24 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 13E9940216EA; Tue, 21 Aug 2018 15:57:38 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-123-147.rdu2.redhat.com [10.10.123.147]) by smtp.corp.redhat.com (Postfix) with ESMTP id E28261010413; Tue, 21 Aug 2018 15:57:36 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 07/23] TPM: Consolidate tpm_send(), transmit_cmd() and tpm_transmit() From: David Howells To: denkenz@gmail.com, jarkko.sakkinen@linux.intel.com, jejb@linux.vnet.ibm.com Cc: keyrings@vger.kernel.org, linux-integrity@vger.kernel.org, tpmdd-devel@lists.sourceforge.net, linux-security-module@vger.kernel.org Date: Tue, 21 Aug 2018 16:57:36 +0100 Message-ID: <153486705643.13066.12702787911194407998.stgit@warthog.procyon.org.uk> In-Reply-To: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> References: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Tue, 21 Aug 2018 15:57:38 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Tue, 21 Aug 2018 15:57:38 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'dhowells@redhat.com' RCPT:'' Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP --- drivers/char/tpm/tpm-dev.c | 17 ++-- drivers/char/tpm/tpm-interface.c | 171 +++++++++++++++++++------------------- drivers/char/tpm/tpm-sysfs.c | 23 ----- drivers/char/tpm/tpm.h | 8 +- include/linux/tpm.h | 7 +- security/keys/trusted.c | 16 ++-- 6 files changed, 117 insertions(+), 125 deletions(-) diff --git a/drivers/char/tpm/tpm-dev.c b/drivers/char/tpm/tpm-dev.c index d9b774e02a1f..6809c2791276 100644 --- a/drivers/char/tpm/tpm-dev.c +++ b/drivers/char/tpm/tpm-dev.c @@ -32,7 +32,10 @@ struct file_priv { struct timer_list user_read_timer; /* user needs to claim result */ struct work_struct work; - u8 data_buffer[TPM_BUFSIZE]; + union { + u8 data_buffer[TPM_BUFSIZE]; + struct tpm_output_header reply; + }; }; static void user_reader_timeout(unsigned long ptr) @@ -119,7 +122,7 @@ static ssize_t tpm_write(struct file *file, const char __user *buf, { struct file_priv *priv = file->private_data; size_t in_size = size; - ssize_t out_size; + long rc; /* cannot perform a write until the read has cleared either via tpm_read or a user_read_timer timeout. @@ -140,14 +143,14 @@ static ssize_t tpm_write(struct file *file, const char __user *buf, } /* atomic tpm command send and result receive */ - out_size = tpm_transmit(priv->chip, priv->data_buffer, - sizeof(priv->data_buffer)); - if (out_size < 0) { + rc = tpm_send_command(priv->chip, priv->data_buffer, + sizeof(priv->data_buffer), NULL); + if (rc < 0) { mutex_unlock(&priv->buffer_mutex); - return out_size; + return rc; } - atomic_set(&priv->data_pending, out_size); + atomic_set(&priv->data_pending, be32_to_cpu(priv->reply.length)); mutex_unlock(&priv->buffer_mutex); /* Set a timeout by which the reader must come claim the result */ diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 9add6034c252..e90f9d2dfaf2 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -329,13 +329,34 @@ unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, } EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration); -/* - * Internal kernel interface to transmit TPM commands +/** + * tpm_send_command - Send a command to the TPM and receive the reply + * @chip: The TPM to communicate with + * @buf: The command and reply buffer + * @bufsiz: The maximum amount of space in buffer for the reply + * @desc: Info about the command being performed for printing purposes (or NULL) + * + * This function sends a command to the TPM and then receives the reply. The + * command must be in the buffer on entry, with the length of the command + * indicated by the command header in the buffer. + * + * The reply is read into the buffer, overwriting the command, up to a maximum + * length of bufsiz. + * + * If the TPM reports an error, desc is used to fabricate an error message. + * + * This function returns 0 on success, a negative kernel error code or a + * positive TPM error code on failure. + * + * In the case that success or a TPM error code is returned, the buffer is + * guaranteed to contain at least a valid reply header. The length of the + * reply is contained in the reply header. */ -ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, - size_t bufsiz) +long tpm_send_command(struct tpm_chip *chip, void *buf, size_t bufsiz, + const char *desc) { - ssize_t rc; + struct tpm_output_header *reply; + long rc; u32 count, ordinal; unsigned long stop; @@ -393,29 +414,30 @@ out_recv: "tpm_transmit: tpm_recv: error %zd\n", rc); out: mutex_unlock(&chip->tpm_mutex); + if (rc < 0) + return rc; + + /* The transmission apparently worked. Sanity check the reply and + * extract the return code. + */ + if (rc < TPM_HEADER_SIZE) + return -EIO; + reply = buf; + + rc = be32_to_cpu(reply->length); + if (rc < TPM_HEADER_SIZE || rc > bufsiz) + return -EIO; + + rc = be32_to_cpu(reply->return_code); + if (rc < 0 || rc >= 0x1000) + return -EIO; + if (rc != 0 && desc) + dev_err(chip->dev, + "A TPM error (%ld) occurred %s\n", rc, desc); return rc; } #define TPM_DIGEST_SIZE 20 -#define TPM_RET_CODE_IDX 6 - -static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, - int len, const char *desc) -{ - int err; - - len = tpm_transmit(chip, (u8 *) cmd, len); - if (len < 0) - return len; - else if (len < TPM_HEADER_SIZE) - return -EFAULT; - - err = be32_to_cpu(cmd->header.out.return_code); - if (err != 0 && desc) - dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc); - - return err; -} #define TPM_INTERNAL_RESULT_SIZE 200 @@ -425,8 +447,8 @@ static const struct tpm_input_header tpm_getcap_header = { .ordinal = cpu_to_be32(TPM_ORD_GET_CAP), }; -ssize_t tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap, - const char *desc) +long tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap, + const char *desc) { struct tpm_cmd_t tpm_cmd; int rc; @@ -447,7 +469,7 @@ ssize_t tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap, tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = subcap_id; } - rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc); + rc = tpm_send_command(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc); if (!rc) *cap = tpm_cmd.params.getcap_out.cap; return rc; @@ -456,15 +478,14 @@ ssize_t tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap, void tpm_gen_interrupt(struct tpm_chip *chip) { struct tpm_cmd_t tpm_cmd; - ssize_t rc; tpm_cmd.header.in = tpm_getcap_header; tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; - rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, - "attempting to determine the timeouts"); + tpm_send_command(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, + "attempting to determine the timeouts"); } EXPORT_SYMBOL_GPL(tpm_gen_interrupt); @@ -477,16 +498,16 @@ static const struct tpm_input_header tpm_startup_header = { .ordinal = cpu_to_be32(TPM_ORD_STARTUP), }; -static int tpm_startup(struct tpm_chip *chip, __be16 startup_type) +static long tpm_startup(struct tpm_chip *chip, struct tpm_cmd_t *start_cmd, + __be16 startup_type) { - struct tpm_cmd_t start_cmd; - start_cmd.header.in = tpm_startup_header; - start_cmd.params.startup_in.startup_type = startup_type; - return transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE, - "attempting to start the TPM"); + start_cmd->header.in = tpm_startup_header; + start_cmd->params.startup_in.startup_type = startup_type; + return tpm_send_command(chip, start_cmd, TPM_INTERNAL_RESULT_SIZE, + "attempting to start the TPM"); } -int tpm_get_timeouts(struct tpm_chip *chip) +long tpm_get_timeouts(struct tpm_chip *chip) { struct tpm_cmd_t tpm_cmd; unsigned long new_timeout[4]; @@ -498,32 +519,28 @@ int tpm_get_timeouts(struct tpm_chip *chip) tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; - rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL); + rc = tpm_send_command(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, + "attempting to determine the timeouts"); if (rc == TPM_ERR_INVALID_POSTINIT) { /* The TPM is not started, we are the first to talk to it. Execute a startup command. */ dev_info(chip->dev, "Issuing TPM_STARTUP"); - if (tpm_startup(chip, TPM_ST_CLEAR)) + if (tpm_startup(chip, &tpm_cmd, TPM_ST_CLEAR)) return rc; tpm_cmd.header.in = tpm_getcap_header; tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; - rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, - NULL); + rc = tpm_send_command(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, + "attempting to determine the timeouts"); } - if (rc) { - dev_err(chip->dev, - "A TPM error (%zd) occurred attempting to determine the timeouts\n", - rc); + if (rc) goto duration; - } - if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 || - be32_to_cpu(tpm_cmd.header.out.length) - != sizeof(tpm_cmd.header.out) + sizeof(u32) + 4 * sizeof(u32)) + if (be32_to_cpu(tpm_cmd.header.out.length) != + sizeof(tpm_cmd.header.out) + sizeof(u32) + 4 * sizeof(u32)) return -EINVAL; old_timeout[0] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.a); @@ -573,8 +590,8 @@ duration: tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION; - rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, - "attempting to determine the durations"); + rc = tpm_send_command(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, + "attempting to determine the durations"); if (rc) return rc; @@ -622,15 +639,11 @@ static struct tpm_input_header continue_selftest_header = { * Returns 0 on success, < 0 in case of fatal error or a value > 0 representing * a TPM error code. */ -static int tpm_continue_selftest(struct tpm_chip *chip) +static int tpm_continue_selftest(struct tpm_chip *chip, struct tpm_cmd_t *cmd) { - int rc; - struct tpm_cmd_t cmd; - - cmd.header.in = continue_selftest_header; - rc = transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE, - "continue selftest"); - return rc; + cmd->header.in = continue_selftest_header; + return tpm_send_command(chip, cmd, CONTINUE_SELFTEST_RESULT_SIZE, + "continue selftest"); } /** @@ -692,8 +705,8 @@ int tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) cmd.header.in = pcrread_header; cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx); - rc = transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE, - "attempting to read a pcr value"); + rc = tpm_send_command(chip, &cmd, READ_PCR_RESULT_SIZE, + "attempting to read a pcr value"); if (rc == 0) memcpy(res_buf, cmd.params.pcrread_out.pcr_result, @@ -726,8 +739,8 @@ int tpm_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash) cmd.header.in = pcrextend_header; cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx); memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE); - return transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, - "attempting extend a PCR value"); + return tpm_send_command(chip, &cmd, EXTEND_PCR_RESULT_SIZE, + "attempting extend a PCR value"); } EXPORT_SYMBOL_GPL(tpm_pcr_extend); @@ -739,9 +752,9 @@ EXPORT_SYMBOL_GPL(tpm_pcr_extend); * Returns 0 on success, < 0 in case of fatal error or a value > 0 representing * a TPM error code. */ -int tpm_do_selftest(struct tpm_chip *chip) +long tpm_do_selftest(struct tpm_chip *chip) { - int rc; + long rc; unsigned int loops; unsigned int delay_msec = 100; unsigned long duration; @@ -751,7 +764,7 @@ int tpm_do_selftest(struct tpm_chip *chip) loops = jiffies_to_msecs(duration) / delay_msec; - rc = tpm_continue_selftest(chip); + rc = tpm_continue_selftest(chip, &cmd); /* This may fail if there was no TPM driver during a suspend/resume * cycle; some may return 10 (BAD_ORDINAL), others 28 (FAILEDSELFTEST) */ @@ -762,7 +775,7 @@ int tpm_do_selftest(struct tpm_chip *chip) /* Attempt to read a PCR value */ cmd.header.in = pcrread_header; cmd.params.pcrread_in.pcr_idx = cpu_to_be32(0); - rc = tpm_transmit(chip, (u8 *) &cmd, READ_PCR_RESULT_SIZE); + rc = tpm_send_command(chip, &cmd, READ_PCR_RESULT_SIZE, NULL); /* Some buggy TPMs will not respond to tpm_tis_ready() for * around 300ms while the self test is ongoing, keep trying * until the self test duration expires. */ @@ -772,13 +785,9 @@ int tpm_do_selftest(struct tpm_chip *chip) continue; } - if (rc < TPM_HEADER_SIZE) - return -EFAULT; - - rc = be32_to_cpu(cmd.header.out.return_code); if (rc == TPM_ERR_DISABLED || rc == TPM_ERR_DEACTIVATED) { dev_info(chip->dev, - "TPM is disabled/deactivated (0x%X)\n", rc); + "TPM is disabled/deactivated (0x%lX)\n", rc); /* TPM is disabled and/or deactivated; driver can * proceed and TPM does handle commands for * suspend/resume correctly @@ -794,12 +803,6 @@ int tpm_do_selftest(struct tpm_chip *chip) } EXPORT_SYMBOL_GPL(tpm_do_selftest); -int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen) -{ - return transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd"); -} -EXPORT_SYMBOL_GPL(tpm_send); - static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask, bool check_cancel, bool *canceled) { @@ -913,14 +916,14 @@ int tpm_pm_suspend(struct device *dev) cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr); memcpy(cmd.params.pcrextend_in.hash, dummy_hash, TPM_DIGEST_SIZE); - rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, - "extending dummy pcr before suspend"); + tpm_send_command(chip, &cmd, EXTEND_PCR_RESULT_SIZE, + "extending dummy pcr before suspend"); } /* now do the actual savestate */ for (try = 0; try < TPM_RETRY; try++) { cmd.header.in = savestate_header; - rc = transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL); + rc = tpm_send_command(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL); /* * If the TPM indicates that it is too busy to respond to @@ -992,9 +995,9 @@ int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max) tpm_cmd.header.in = tpm_getrandom_header; tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes); - err = transmit_cmd(chip, &tpm_cmd, - TPM_GETRANDOM_RESULT_SIZE + num_bytes, - "attempting get random"); + err = tpm_send_command(chip, &tpm_cmd, + TPM_GETRANDOM_RESULT_SIZE + num_bytes, + "attempting get random"); if (err) break; diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c index d8da83a1d11c..ad3b01882b15 100644 --- a/drivers/char/tpm/tpm-sysfs.c +++ b/drivers/char/tpm/tpm-sysfs.c @@ -21,25 +21,6 @@ #include #include "tpm.h" -/* XXX for now this helper is duplicated in tpm-interface.c */ -static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, - int len, const char *desc) -{ - int err; - - len = tpm_transmit(chip, (u8 *) cmd, len); - if (len < 0) - return len; - else if (len < TPM_HEADER_SIZE) - return -EFAULT; - - err = be32_to_cpu(cmd->header.out.return_code); - if (err != 0 && desc) - dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc); - - return err; -} - #define READ_PUBEK_RESULT_SIZE 314 static struct tpm_input_header tpm_readpubek_header = { .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND), @@ -58,8 +39,8 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr, struct tpm_chip *chip = dev_get_drvdata(dev); tpm_cmd.header.in = tpm_readpubek_header; - err = transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE, - "attempting to read the PUBEK"); + err = tpm_send_command(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE, + "attempting to read the PUBEK"); if (err) goto out; diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 2a1be0ec2fbd..912eba092e62 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -306,13 +306,11 @@ struct tpm_cmd_t { tpm_cmd_params params; } __packed; -ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *); +extern long tpm_getcap(struct device *, __be32, cap_t *, const char *); -ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, - size_t bufsiz); -extern int tpm_get_timeouts(struct tpm_chip *); +extern long tpm_get_timeouts(struct tpm_chip *); extern void tpm_gen_interrupt(struct tpm_chip *); -extern int tpm_do_selftest(struct tpm_chip *); +extern long tpm_do_selftest(struct tpm_chip *); extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32); extern struct tpm_chip* tpm_register_hardware(struct device *, const struct tpm_class_ops *ops); diff --git a/include/linux/tpm.h b/include/linux/tpm.h index c213e09b7d81..f4e14405f5cf 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -51,7 +51,8 @@ extern void tpm_chip_put(struct tpm_chip *chip); extern int tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf); extern int tpm_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash); -extern int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen); +extern long tpm_send_command(struct tpm_chip *chip, void *buf, size_t buflen, + const char *desc); extern int tpm_get_random(struct tpm_chip *chip, u8 *data, size_t max); #else static inline struct tpm_chip *tpm_chip_find_get(int chip_num) @@ -67,7 +68,9 @@ static inline int tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) static inline int tpm_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash) { return -ENODEV; } -static inline int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen) { +static inline long tpm_send_command(struct tpm_chip *chip, void *buf, size_t buflen, + const char *desc) +{ return -ENODEV; } static inline int tpm_get_random(struct tpm_chip *chip, u8 *data, size_t max) { diff --git a/security/keys/trusted.c b/security/keys/trusted.c index adb0caa5c38d..943c65b53201 100644 --- a/security/keys/trusted.c +++ b/security/keys/trusted.c @@ -355,12 +355,12 @@ out: * own TPM command packets using the drivers send function. */ static int trusted_tpm_send(struct tpm_chip *chip, unsigned char *cmd, - size_t buflen) + size_t buflen, const char *desc) { int rc; dump_tpm_buf(cmd); - rc = tpm_send(chip, cmd, buflen); + rc = tpm_send_command(chip, cmd, buflen, desc); dump_tpm_buf(cmd); if (rc > 0) /* Can't return positive return codes values to keyctl */ @@ -410,7 +410,8 @@ static int osap(struct tpm_chip *chip, store32(tb, handle); storebytes(tb, ononce, TPM_NONCE_SIZE); - ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE); + ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE, + "creating OSAP session"); if (ret < 0) return ret; @@ -435,7 +436,8 @@ static int oiap(struct tpm_chip *chip, struct tpm_buf *tb, uint32_t *handle, store16(tb, TPM_TAG_RQU_COMMAND); store32(tb, TPM_OIAP_SIZE); store32(tb, TPM_ORD_OIAP); - ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE); + ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE, + "creating OIAP session"); if (ret < 0) return ret; @@ -544,7 +546,8 @@ static int tpm_seal(struct tpm_chip *chip, store8(tb, cont); storebytes(tb, td->pubauth, SHA1_DIGEST_SIZE); - ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE); + ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE, + "sealing data"); if (ret < 0) goto out; @@ -637,7 +640,8 @@ static int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, store8(tb, cont); storebytes(tb, authdata2, SHA1_DIGEST_SIZE); - ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE); + ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE, + "unsealing data"); if (ret < 0) { pr_info("trusted_key: authhmac failed (%d)\n", ret); return ret; From patchwork Tue Aug 21 15:57:43 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 10571943 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E8647921 for ; Tue, 21 Aug 2018 15:57:51 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CF85A2A97A for ; Tue, 21 Aug 2018 15:57:51 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C1FA82A9AA; Tue, 21 Aug 2018 15:57:51 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5742B2A976 for ; Tue, 21 Aug 2018 15:57:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728119AbeHUTSa (ORCPT ); Tue, 21 Aug 2018 15:18:30 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:45124 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726967AbeHUTS3 (ORCPT ); Tue, 21 Aug 2018 15:18:29 -0400 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id ED689402178A; Tue, 21 Aug 2018 15:57:44 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-123-147.rdu2.redhat.com [10.10.123.147]) by smtp.corp.redhat.com (Postfix) with ESMTP id ACC33A9A06; Tue, 21 Aug 2018 15:57:43 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 08/23] TPMLIB: Break TPM bits out of security/keys/trusted.c From: David Howells To: denkenz@gmail.com, jarkko.sakkinen@linux.intel.com, jejb@linux.vnet.ibm.com Cc: keyrings@vger.kernel.org, linux-integrity@vger.kernel.org, tpmdd-devel@lists.sourceforge.net, linux-security-module@vger.kernel.org Date: Tue, 21 Aug 2018 16:57:43 +0100 Message-ID: <153486706322.13066.3105842100625841410.stgit@warthog.procyon.org.uk> In-Reply-To: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> References: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Tue, 21 Aug 2018 15:57:45 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Tue, 21 Aug 2018 15:57:45 +0000 (UTC) for IP:'10.11.54.5' DOMAIN:'int-mx05.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'dhowells@redhat.com' RCPT:'' Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Break the TPM bits out of security/keys/trusted.c into their own call wrapper library. Signed-off-by: David Howells --- drivers/char/tpm/Makefile | 2 drivers/char/tpm/tpm-library.c | 682 ++++++++++++++++++++++++++++++++++++++++ drivers/char/tpm/tpm-library.h | 83 +++++ include/linux/tpm.h | 38 ++ security/keys/trusted.c | 646 -------------------------------------- security/keys/trusted.h | 80 ----- 6 files changed, 804 insertions(+), 727 deletions(-) create mode 100644 drivers/char/tpm/tpm-library.c create mode 100644 drivers/char/tpm/tpm-library.h diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index b179052cd81b..cea6a4d05920 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile @@ -2,7 +2,7 @@ # Makefile for the kernel tpm device drivers. # obj-$(CONFIG_TCG_TPM) += tpm.o -tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o +tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-library.o tpm-$(CONFIG_ACPI) += tpm_ppi.o ifdef CONFIG_ACPI diff --git a/drivers/char/tpm/tpm-library.c b/drivers/char/tpm/tpm-library.c new file mode 100644 index 000000000000..1be4f71cabcb --- /dev/null +++ b/drivers/char/tpm/tpm-library.c @@ -0,0 +1,682 @@ +/* TPM call wrapper library. + * + * Copyright (C) 2010 IBM Corporation + * + * Author: + * David Safford + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * See Documentation/security/keys-trusted-encrypted.txt + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tpm-library.h" + +static const char hmac_alg[] = "hmac(sha1)"; +static const char hash_alg[] = "sha1"; + +struct sdesc { + struct shash_desc shash; + char ctx[]; +}; + +static struct crypto_shash *hashalg; +static struct crypto_shash *hmacalg; + +static struct sdesc *init_sdesc(struct crypto_shash *alg) +{ + struct sdesc *sdesc; + int size; + + size = sizeof(struct shash_desc) + crypto_shash_descsize(alg); + sdesc = kmalloc(size, GFP_KERNEL); + if (!sdesc) + return ERR_PTR(-ENOMEM); + sdesc->shash.tfm = alg; + sdesc->shash.flags = 0x0; + return sdesc; +} + +static int TSS_sha1(const unsigned char *data, unsigned int datalen, + unsigned char *digest) +{ + struct sdesc *sdesc; + int ret; + + sdesc = init_sdesc(hashalg); + if (IS_ERR(sdesc)) { + pr_info("trusted_key: can't alloc %s\n", hash_alg); + return PTR_ERR(sdesc); + } + + ret = crypto_shash_digest(&sdesc->shash, data, datalen, digest); + kfree(sdesc); + return ret; +} + +static int TSS_rawhmac(unsigned char *digest, const unsigned char *key, + unsigned int keylen, ...) +{ + struct sdesc *sdesc; + va_list argp; + unsigned int dlen; + unsigned char *data; + int ret; + + sdesc = init_sdesc(hmacalg); + if (IS_ERR(sdesc)) { + pr_info("trusted_key: can't alloc %s\n", hmac_alg); + return PTR_ERR(sdesc); + } + + ret = crypto_shash_setkey(hmacalg, key, keylen); + if (ret < 0) + goto out; + ret = crypto_shash_init(&sdesc->shash); + if (ret < 0) + goto out; + + va_start(argp, keylen); + for (;;) { + dlen = va_arg(argp, unsigned int); + if (dlen == 0) + break; + data = va_arg(argp, unsigned char *); + if (data == NULL) { + ret = -EINVAL; + break; + } + ret = crypto_shash_update(&sdesc->shash, data, dlen); + if (ret < 0) + break; + } + va_end(argp); + if (!ret) + ret = crypto_shash_final(&sdesc->shash, digest); +out: + kfree(sdesc); + return ret; +} + +/* + * calculate authorization info fields to send to TPM + */ +static int TSS_authhmac(unsigned char *digest, const unsigned char *key, + unsigned int keylen, unsigned char *h1, + unsigned char *h2, unsigned char h3, ...) +{ + unsigned char paramdigest[SHA1_DIGEST_SIZE]; + struct sdesc *sdesc; + unsigned int dlen; + unsigned char *data; + unsigned char c; + int ret; + va_list argp; + + sdesc = init_sdesc(hashalg); + if (IS_ERR(sdesc)) { + pr_info("trusted_key: can't alloc %s\n", hash_alg); + return PTR_ERR(sdesc); + } + + c = h3; + ret = crypto_shash_init(&sdesc->shash); + if (ret < 0) + goto out; + va_start(argp, h3); + for (;;) { + dlen = va_arg(argp, unsigned int); + if (dlen == 0) + break; + data = va_arg(argp, unsigned char *); + if (!data) { + ret = -EINVAL; + break; + } + ret = crypto_shash_update(&sdesc->shash, data, dlen); + if (ret < 0) + break; + } + va_end(argp); + if (!ret) + ret = crypto_shash_final(&sdesc->shash, paramdigest); + if (!ret) + 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; +} + +/* + * verify the AUTH1_COMMAND (Seal) result from TPM + */ +static int TSS_checkhmac1(unsigned char *buffer, + const uint32_t command, + const unsigned char *ononce, + const unsigned char *key, + unsigned int keylen, ...) +{ + uint32_t bufsize; + uint16_t tag; + uint32_t ordinal; + uint32_t result; + unsigned char *enonce; + unsigned char *continueflag; + unsigned char *authdata; + unsigned char testhmac[SHA1_DIGEST_SIZE]; + unsigned char paramdigest[SHA1_DIGEST_SIZE]; + struct sdesc *sdesc; + unsigned int dlen; + unsigned int dpos; + va_list argp; + int ret; + + bufsize = LOAD32(buffer, TPM_SIZE_OFFSET); + tag = LOAD16(buffer, 0); + ordinal = command; + result = LOAD32N(buffer, TPM_RETURN_OFFSET); + if (tag == TPM_TAG_RSP_COMMAND) + return 0; + if (tag != TPM_TAG_RSP_AUTH1_COMMAND) + return -EINVAL; + authdata = buffer + bufsize - SHA1_DIGEST_SIZE; + continueflag = authdata - 1; + enonce = continueflag - TPM_NONCE_SIZE; + + sdesc = init_sdesc(hashalg); + if (IS_ERR(sdesc)) { + pr_info("trusted_key: can't alloc %s\n", hash_alg); + return PTR_ERR(sdesc); + } + ret = crypto_shash_init(&sdesc->shash); + if (ret < 0) + goto out; + ret = crypto_shash_update(&sdesc->shash, (const u8 *)&result, + sizeof result); + if (ret < 0) + goto out; + ret = crypto_shash_update(&sdesc->shash, (const u8 *)&ordinal, + sizeof ordinal); + if (ret < 0) + goto out; + va_start(argp, keylen); + for (;;) { + dlen = va_arg(argp, unsigned int); + if (dlen == 0) + break; + dpos = va_arg(argp, unsigned int); + ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen); + if (ret < 0) + break; + } + va_end(argp); + if (!ret) + 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: + kfree(sdesc); + return ret; +} + +/* + * verify the AUTH2_COMMAND (unseal) result from TPM + */ +static int TSS_checkhmac2(unsigned char *buffer, + const uint32_t command, + const unsigned char *ononce, + const unsigned char *key1, + unsigned int keylen1, + const unsigned char *key2, + unsigned int keylen2, ...) +{ + uint32_t bufsize; + uint16_t tag; + uint32_t ordinal; + uint32_t result; + unsigned char *enonce1; + unsigned char *continueflag1; + unsigned char *authdata1; + unsigned char *enonce2; + unsigned char *continueflag2; + unsigned char *authdata2; + unsigned char testhmac1[SHA1_DIGEST_SIZE]; + unsigned char testhmac2[SHA1_DIGEST_SIZE]; + unsigned char paramdigest[SHA1_DIGEST_SIZE]; + struct sdesc *sdesc; + unsigned int dlen; + unsigned int dpos; + va_list argp; + int ret; + + bufsize = LOAD32(buffer, TPM_SIZE_OFFSET); + tag = LOAD16(buffer, 0); + ordinal = command; + result = LOAD32N(buffer, TPM_RETURN_OFFSET); + + if (tag == TPM_TAG_RSP_COMMAND) + return 0; + if (tag != TPM_TAG_RSP_AUTH2_COMMAND) + return -EINVAL; + authdata1 = buffer + bufsize - (SHA1_DIGEST_SIZE + 1 + + SHA1_DIGEST_SIZE + SHA1_DIGEST_SIZE); + authdata2 = buffer + bufsize - (SHA1_DIGEST_SIZE); + continueflag1 = authdata1 - 1; + continueflag2 = authdata2 - 1; + enonce1 = continueflag1 - TPM_NONCE_SIZE; + enonce2 = continueflag2 - TPM_NONCE_SIZE; + + sdesc = init_sdesc(hashalg); + if (IS_ERR(sdesc)) { + pr_info("trusted_key: can't alloc %s\n", hash_alg); + return PTR_ERR(sdesc); + } + ret = crypto_shash_init(&sdesc->shash); + if (ret < 0) + goto out; + ret = crypto_shash_update(&sdesc->shash, (const u8 *)&result, + sizeof result); + if (ret < 0) + goto out; + ret = crypto_shash_update(&sdesc->shash, (const u8 *)&ordinal, + sizeof ordinal); + if (ret < 0) + goto out; + + va_start(argp, keylen2); + for (;;) { + dlen = va_arg(argp, unsigned int); + if (dlen == 0) + break; + dpos = va_arg(argp, unsigned int); + ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen); + if (ret < 0) + break; + } + va_end(argp); + if (!ret) + 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: + kfree(sdesc); + return ret; +} + +/* + * For key specific tpm requests, we will generate and send our + * own TPM command packets using the drivers send function. + */ +static int trusted_tpm_send(struct tpm_chip *chip, unsigned char *cmd, + size_t buflen, const char *desc) +{ + int rc; + + dump_tpm_buf(cmd); + rc = tpm_send_command(chip, cmd, buflen, desc); + dump_tpm_buf(cmd); + if (rc > 0) + /* Can't return positive return codes values to keyctl */ + rc = -EPERM; + return rc; +} + +/* + * Create an object specific authorisation protocol (OSAP) session + */ +static int osap(struct tpm_chip *chip, + struct tpm_buf *tb, struct osapsess *s, + const unsigned char *key, uint16_t type, uint32_t handle) +{ + unsigned char enonce[TPM_NONCE_SIZE]; + unsigned char ononce[TPM_NONCE_SIZE]; + int ret; + + ret = tpm_get_random(chip, ononce, TPM_NONCE_SIZE); + if (ret != TPM_NONCE_SIZE) + return ret; + + INIT_BUF(tb); + store16(tb, TPM_TAG_RQU_COMMAND); + store32(tb, TPM_OSAP_SIZE); + store32(tb, TPM_ORD_OSAP); + store16(tb, type); + store32(tb, handle); + storebytes(tb, ononce, TPM_NONCE_SIZE); + + ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE, + "creating OSAP session"); + if (ret < 0) + return ret; + + s->handle = LOAD32(tb->data, TPM_DATA_OFFSET); + memcpy(s->enonce, &(tb->data[TPM_DATA_OFFSET + sizeof(uint32_t)]), + TPM_NONCE_SIZE); + memcpy(enonce, &(tb->data[TPM_DATA_OFFSET + sizeof(uint32_t) + + TPM_NONCE_SIZE]), TPM_NONCE_SIZE); + return TSS_rawhmac(s->secret, key, SHA1_DIGEST_SIZE, TPM_NONCE_SIZE, + enonce, TPM_NONCE_SIZE, ononce, 0, 0); +} + +/* + * Create an object independent authorisation protocol (oiap) session + */ +static int oiap(struct tpm_chip *chip, struct tpm_buf *tb, uint32_t *handle, + unsigned char *nonce) +{ + int ret; + + INIT_BUF(tb); + store16(tb, TPM_TAG_RQU_COMMAND); + store32(tb, TPM_OIAP_SIZE); + store32(tb, TPM_ORD_OIAP); + ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE, + "creating OIAP session"); + if (ret < 0) + return ret; + + *handle = LOAD32(tb->data, TPM_DATA_OFFSET); + memcpy(nonce, &tb->data[TPM_DATA_OFFSET + sizeof(uint32_t)], + TPM_NONCE_SIZE); + return 0; +} + +struct tpm_digests { + unsigned char encauth[SHA1_DIGEST_SIZE]; + unsigned char pubauth[SHA1_DIGEST_SIZE]; + unsigned char xorwork[SHA1_DIGEST_SIZE * 2]; + unsigned char xorhash[SHA1_DIGEST_SIZE]; + unsigned char nonceodd[TPM_NONCE_SIZE]; +}; + +/* + * Have the TPM seal(encrypt) the trusted key, possibly based on + * Platform Configuration Registers (PCRs). AUTH1 for sealing key. + */ +int tpm_seal(struct tpm_chip *chip, struct tpm_buf *tb, uint16_t keytype, + uint32_t keyhandle, const unsigned char *keyauth, + const unsigned char *data, uint32_t datalen, + unsigned char *blob, uint32_t *bloblen, + const unsigned char *blobauth, + const unsigned char *pcrinfo, uint32_t pcrinfosize) +{ + struct osapsess sess; + struct tpm_digests *td; + unsigned char cont; + uint32_t ordinal; + uint32_t pcrsize; + uint32_t datsize; + int sealinfosize; + int encdatasize; + int storedsize; + int ret; + int i; + + /* alloc some work space for all the hashes */ + td = kmalloc(sizeof *td, GFP_KERNEL); + if (!td) + return -ENOMEM; + + /* get session for sealing key */ + ret = osap(chip, tb, &sess, keyauth, keytype, keyhandle); + if (ret < 0) + goto out; + dump_sess(&sess); + + /* calculate encrypted authorization value */ + memcpy(td->xorwork, sess.secret, SHA1_DIGEST_SIZE); + memcpy(td->xorwork + SHA1_DIGEST_SIZE, sess.enonce, SHA1_DIGEST_SIZE); + ret = TSS_sha1(td->xorwork, SHA1_DIGEST_SIZE * 2, td->xorhash); + if (ret < 0) + goto out; + + ret = tpm_get_random(chip, td->nonceodd, TPM_NONCE_SIZE); + if (ret != TPM_NONCE_SIZE) + goto out; + ordinal = htonl(TPM_ORD_SEAL); + datsize = htonl(datalen); + pcrsize = htonl(pcrinfosize); + cont = 0; + + /* encrypt data authorization key */ + for (i = 0; i < SHA1_DIGEST_SIZE; ++i) + td->encauth[i] = td->xorhash[i] ^ blobauth[i]; + + /* calculate authorization HMAC value */ + if (pcrinfosize == 0) { + /* no pcr info specified */ + 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 */ + 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) + goto out; + + /* build and send the TPM request packet */ + INIT_BUF(tb); + store16(tb, TPM_TAG_RQU_AUTH1_COMMAND); + store32(tb, TPM_SEAL_SIZE + pcrinfosize + datalen); + store32(tb, TPM_ORD_SEAL); + store32(tb, keyhandle); + storebytes(tb, td->encauth, SHA1_DIGEST_SIZE); + store32(tb, pcrinfosize); + storebytes(tb, pcrinfo, pcrinfosize); + store32(tb, datalen); + storebytes(tb, data, datalen); + store32(tb, sess.handle); + storebytes(tb, td->nonceodd, TPM_NONCE_SIZE); + store8(tb, cont); + storebytes(tb, td->pubauth, SHA1_DIGEST_SIZE); + + ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE, + "sealing data"); + if (ret < 0) + goto out; + + /* calculate the size of the returned Blob */ + 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; + + /* check the HMAC in the response */ + ret = TSS_checkhmac1(tb->data, ordinal, td->nonceodd, sess.secret, + SHA1_DIGEST_SIZE, storedsize, TPM_DATA_OFFSET, 0, + 0); + + /* copy the returned blob to caller */ + if (!ret) { + memcpy(blob, tb->data + TPM_DATA_OFFSET, storedsize); + *bloblen = storedsize; + } +out: + kfree(td); + return ret; +} +EXPORT_SYMBOL_GPL(tpm_seal); + +/* + * use the AUTH2_COMMAND form of unseal, to authorize both key and blob + */ +int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, + uint32_t keyhandle, const unsigned char *keyauth, + const unsigned char *blob, int bloblen, + const unsigned char *blobauth, + unsigned char *data, unsigned int *datalen) +{ + unsigned char nonceodd[TPM_NONCE_SIZE]; + unsigned char enonce1[TPM_NONCE_SIZE]; + unsigned char enonce2[TPM_NONCE_SIZE]; + unsigned char authdata1[SHA1_DIGEST_SIZE]; + unsigned char authdata2[SHA1_DIGEST_SIZE]; + uint32_t authhandle1 = 0; + uint32_t authhandle2 = 0; + unsigned char cont = 0; + uint32_t ordinal; + uint32_t keyhndl; + int ret; + + /* sessions for unsealing key and data */ + ret = oiap(chip, tb, &authhandle1, enonce1); + if (ret < 0) { + pr_info("trusted_key: oiap failed (%d)\n", ret); + return ret; + } + ret = oiap(chip, tb, &authhandle2, enonce2); + if (ret < 0) { + pr_info("trusted_key: oiap failed (%d)\n", ret); + return ret; + } + + ordinal = htonl(TPM_ORD_UNSEAL); + keyhndl = htonl(SRKHANDLE); + ret = tpm_get_random(chip, nonceodd, TPM_NONCE_SIZE); + if (ret != TPM_NONCE_SIZE) { + pr_info("trusted_key: tpm_get_random failed (%d)\n", ret); + return ret; + } + 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); + store16(tb, TPM_TAG_RQU_AUTH2_COMMAND); + store32(tb, TPM_UNSEAL_SIZE + bloblen); + store32(tb, TPM_ORD_UNSEAL); + store32(tb, keyhandle); + storebytes(tb, blob, bloblen); + store32(tb, authhandle1); + storebytes(tb, nonceodd, TPM_NONCE_SIZE); + store8(tb, cont); + storebytes(tb, authdata1, SHA1_DIGEST_SIZE); + store32(tb, authhandle2); + storebytes(tb, nonceodd, TPM_NONCE_SIZE); + store8(tb, cont); + storebytes(tb, authdata2, SHA1_DIGEST_SIZE); + + ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE, + "unsealing data"); + if (ret < 0) { + pr_info("trusted_key: authhmac failed (%d)\n", ret); + return ret; + } + + *datalen = LOAD32(tb->data, TPM_DATA_OFFSET); + ret = TSS_checkhmac2(tb->data, ordinal, nonceodd, + keyauth, SHA1_DIGEST_SIZE, + blobauth, SHA1_DIGEST_SIZE, + sizeof(uint32_t), TPM_DATA_OFFSET, + *datalen, TPM_DATA_OFFSET + sizeof(uint32_t), 0, + 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 0; +} +EXPORT_SYMBOL_GPL(tpm_unseal); + +void trusted_shash_release(void) +{ + if (hashalg) + crypto_free_shash(hashalg); + if (hmacalg) + crypto_free_shash(hmacalg); +} +EXPORT_SYMBOL_GPL(trusted_shash_release); + +int trusted_shash_alloc(void) +{ + int ret; + + hmacalg = crypto_alloc_shash(hmac_alg, 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(hmacalg)) { + pr_info("trusted_key: could not allocate crypto %s\n", + hmac_alg); + return PTR_ERR(hmacalg); + } + + hashalg = crypto_alloc_shash(hash_alg, 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(hashalg)) { + pr_info("trusted_key: could not allocate crypto %s\n", + hash_alg); + ret = PTR_ERR(hashalg); + goto hashalg_fail; + } + + return 0; + +hashalg_fail: + crypto_free_shash(hmacalg); + return ret; +} +EXPORT_SYMBOL_GPL(trusted_shash_alloc); diff --git a/drivers/char/tpm/tpm-library.h b/drivers/char/tpm/tpm-library.h new file mode 100644 index 000000000000..eec1dfe26c2a --- /dev/null +++ b/drivers/char/tpm/tpm-library.h @@ -0,0 +1,83 @@ +/* TPM call wrapper library internal definitions. + * + * Copyright (C) 2010 IBM Corporation + * + * Author: + * David Safford + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + */ + + +#define LOAD32(buffer, offset) (ntohl(*(uint32_t *)&buffer[offset])) +#define LOAD32N(buffer, offset) (*(uint32_t *)&buffer[offset]) +#define LOAD16(buffer, offset) (ntohs(*(uint16_t *)&buffer[offset])) + +struct osapsess { + uint32_t handle; + unsigned char secret[SHA1_DIGEST_SIZE]; + unsigned char enonce[TPM_NONCE_SIZE]; +}; + +static inline void store8(struct tpm_buf *buf, const unsigned char value) +{ + buf->data[buf->len++] = value; +} + +static inline void store16(struct tpm_buf *buf, const uint16_t value) +{ + *(uint16_t *) & buf->data[buf->len] = htons(value); + buf->len += sizeof value; +} + +static inline void store32(struct tpm_buf *buf, const uint32_t value) +{ + *(uint32_t *) & buf->data[buf->len] = htonl(value); + buf->len += sizeof value; +} + +static inline void storebytes(struct tpm_buf *buf, const unsigned char *in, + const int len) +{ + memcpy(buf->data + buf->len, in, len); + buf->len += len; +} + +/* + * Debugging + */ +#define TPM_DEBUG 0 + +#ifdef TPM_DEBUG +static inline void dump_sess(struct osapsess *s) +{ + print_hex_dump(KERN_INFO, "trusted-key: handle ", DUMP_PREFIX_NONE, + 16, 1, &s->handle, 4, 0); + pr_info("trusted-key: secret:\n"); + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, + 16, 1, &s->secret, SHA1_DIGEST_SIZE, 0); + pr_info("trusted-key: enonce:\n"); + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, + 16, 1, &s->enonce, SHA1_DIGEST_SIZE, 0); +} + +static inline void dump_tpm_buf(unsigned char *buf) +{ + int len; + + pr_info("\ntrusted-key: tpm buffer\n"); + len = LOAD32(buf, TPM_SIZE_OFFSET); + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, buf, len, 0); +} + +#else +static inline void dump_sess(struct osapsess *s) +{ +} + +static inline void dump_tpm_buf(unsigned char *buf) +{ +} +#endif diff --git a/include/linux/tpm.h b/include/linux/tpm.h index f4e14405f5cf..5d8caf56c272 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -77,4 +77,42 @@ static inline int tpm_get_random(struct tpm_chip *chip, u8 *data, size_t max) { return -ENODEV; } #endif + +/* + * TPM call library. + */ +/* implementation specific TPM constants */ +#define MAX_PCRINFO_SIZE 64 +#define MAX_BUF_SIZE 512 +#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_SIZE_OFFSET 2 +#define TPM_RETURN_OFFSET 6 +#define TPM_DATA_OFFSET 10 + +struct tpm_buf { + int len; + unsigned char data[MAX_BUF_SIZE]; +}; + +#define INIT_BUF(tb) (tb->len = 0) + +extern void trusted_shash_release(void); +extern int trusted_shash_alloc(void); + +extern int tpm_seal(struct tpm_chip *chip, struct tpm_buf *tb, uint16_t keytype, + uint32_t keyhandle, const unsigned char *keyauth, + const unsigned char *data, uint32_t datalen, + unsigned char *blob, uint32_t *bloblen, + const unsigned char *blobauth, + const unsigned char *pcrinfo, uint32_t pcrinfosize); +extern int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, + uint32_t keyhandle, const unsigned char *keyauth, + const unsigned char *blob, int bloblen, + const unsigned char *blobauth, + unsigned char *data, unsigned int *datalen); + #endif diff --git a/security/keys/trusted.c b/security/keys/trusted.c index 943c65b53201..83c6a485e62a 100644 --- a/security/keys/trusted.c +++ b/security/keys/trusted.c @@ -31,343 +31,6 @@ #include "trusted.h" -static const char hmac_alg[] = "hmac(sha1)"; -static const char hash_alg[] = "sha1"; - -struct sdesc { - struct shash_desc shash; - char ctx[]; -}; - -static struct crypto_shash *hashalg; -static struct crypto_shash *hmacalg; - -static struct sdesc *init_sdesc(struct crypto_shash *alg) -{ - struct sdesc *sdesc; - int size; - - size = sizeof(struct shash_desc) + crypto_shash_descsize(alg); - sdesc = kmalloc(size, GFP_KERNEL); - if (!sdesc) - return ERR_PTR(-ENOMEM); - sdesc->shash.tfm = alg; - sdesc->shash.flags = 0x0; - return sdesc; -} - -static int TSS_sha1(const unsigned char *data, unsigned int datalen, - unsigned char *digest) -{ - struct sdesc *sdesc; - int ret; - - sdesc = init_sdesc(hashalg); - if (IS_ERR(sdesc)) { - pr_info("trusted_key: can't alloc %s\n", hash_alg); - return PTR_ERR(sdesc); - } - - ret = crypto_shash_digest(&sdesc->shash, data, datalen, digest); - kfree(sdesc); - return ret; -} - -static int TSS_rawhmac(unsigned char *digest, const unsigned char *key, - unsigned int keylen, ...) -{ - struct sdesc *sdesc; - va_list argp; - unsigned int dlen; - unsigned char *data; - int ret; - - sdesc = init_sdesc(hmacalg); - if (IS_ERR(sdesc)) { - pr_info("trusted_key: can't alloc %s\n", hmac_alg); - return PTR_ERR(sdesc); - } - - ret = crypto_shash_setkey(hmacalg, key, keylen); - if (ret < 0) - goto out; - ret = crypto_shash_init(&sdesc->shash); - if (ret < 0) - goto out; - - va_start(argp, keylen); - for (;;) { - dlen = va_arg(argp, unsigned int); - if (dlen == 0) - break; - data = va_arg(argp, unsigned char *); - if (data == NULL) { - ret = -EINVAL; - break; - } - ret = crypto_shash_update(&sdesc->shash, data, dlen); - if (ret < 0) - break; - } - va_end(argp); - if (!ret) - ret = crypto_shash_final(&sdesc->shash, digest); -out: - kfree(sdesc); - return ret; -} - -/* - * calculate authorization info fields to send to TPM - */ -static int TSS_authhmac(unsigned char *digest, const unsigned char *key, - unsigned int keylen, unsigned char *h1, - unsigned char *h2, unsigned char h3, ...) -{ - unsigned char paramdigest[SHA1_DIGEST_SIZE]; - struct sdesc *sdesc; - unsigned int dlen; - unsigned char *data; - unsigned char c; - int ret; - va_list argp; - - sdesc = init_sdesc(hashalg); - if (IS_ERR(sdesc)) { - pr_info("trusted_key: can't alloc %s\n", hash_alg); - return PTR_ERR(sdesc); - } - - c = h3; - ret = crypto_shash_init(&sdesc->shash); - if (ret < 0) - goto out; - va_start(argp, h3); - for (;;) { - dlen = va_arg(argp, unsigned int); - if (dlen == 0) - break; - data = va_arg(argp, unsigned char *); - if (!data) { - ret = -EINVAL; - break; - } - ret = crypto_shash_update(&sdesc->shash, data, dlen); - if (ret < 0) - break; - } - va_end(argp); - if (!ret) - ret = crypto_shash_final(&sdesc->shash, paramdigest); - if (!ret) - 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; -} - -/* - * verify the AUTH1_COMMAND (Seal) result from TPM - */ -static int TSS_checkhmac1(unsigned char *buffer, - const uint32_t command, - const unsigned char *ononce, - const unsigned char *key, - unsigned int keylen, ...) -{ - uint32_t bufsize; - uint16_t tag; - uint32_t ordinal; - uint32_t result; - unsigned char *enonce; - unsigned char *continueflag; - unsigned char *authdata; - unsigned char testhmac[SHA1_DIGEST_SIZE]; - unsigned char paramdigest[SHA1_DIGEST_SIZE]; - struct sdesc *sdesc; - unsigned int dlen; - unsigned int dpos; - va_list argp; - int ret; - - bufsize = LOAD32(buffer, TPM_SIZE_OFFSET); - tag = LOAD16(buffer, 0); - ordinal = command; - result = LOAD32N(buffer, TPM_RETURN_OFFSET); - if (tag == TPM_TAG_RSP_COMMAND) - return 0; - if (tag != TPM_TAG_RSP_AUTH1_COMMAND) - return -EINVAL; - authdata = buffer + bufsize - SHA1_DIGEST_SIZE; - continueflag = authdata - 1; - enonce = continueflag - TPM_NONCE_SIZE; - - sdesc = init_sdesc(hashalg); - if (IS_ERR(sdesc)) { - pr_info("trusted_key: can't alloc %s\n", hash_alg); - return PTR_ERR(sdesc); - } - ret = crypto_shash_init(&sdesc->shash); - if (ret < 0) - goto out; - ret = crypto_shash_update(&sdesc->shash, (const u8 *)&result, - sizeof result); - if (ret < 0) - goto out; - ret = crypto_shash_update(&sdesc->shash, (const u8 *)&ordinal, - sizeof ordinal); - if (ret < 0) - goto out; - va_start(argp, keylen); - for (;;) { - dlen = va_arg(argp, unsigned int); - if (dlen == 0) - break; - dpos = va_arg(argp, unsigned int); - ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen); - if (ret < 0) - break; - } - va_end(argp); - if (!ret) - 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: - kfree(sdesc); - return ret; -} - -/* - * verify the AUTH2_COMMAND (unseal) result from TPM - */ -static int TSS_checkhmac2(unsigned char *buffer, - const uint32_t command, - const unsigned char *ononce, - const unsigned char *key1, - unsigned int keylen1, - const unsigned char *key2, - unsigned int keylen2, ...) -{ - uint32_t bufsize; - uint16_t tag; - uint32_t ordinal; - uint32_t result; - unsigned char *enonce1; - unsigned char *continueflag1; - unsigned char *authdata1; - unsigned char *enonce2; - unsigned char *continueflag2; - unsigned char *authdata2; - unsigned char testhmac1[SHA1_DIGEST_SIZE]; - unsigned char testhmac2[SHA1_DIGEST_SIZE]; - unsigned char paramdigest[SHA1_DIGEST_SIZE]; - struct sdesc *sdesc; - unsigned int dlen; - unsigned int dpos; - va_list argp; - int ret; - - bufsize = LOAD32(buffer, TPM_SIZE_OFFSET); - tag = LOAD16(buffer, 0); - ordinal = command; - result = LOAD32N(buffer, TPM_RETURN_OFFSET); - - if (tag == TPM_TAG_RSP_COMMAND) - return 0; - if (tag != TPM_TAG_RSP_AUTH2_COMMAND) - return -EINVAL; - authdata1 = buffer + bufsize - (SHA1_DIGEST_SIZE + 1 - + SHA1_DIGEST_SIZE + SHA1_DIGEST_SIZE); - authdata2 = buffer + bufsize - (SHA1_DIGEST_SIZE); - continueflag1 = authdata1 - 1; - continueflag2 = authdata2 - 1; - enonce1 = continueflag1 - TPM_NONCE_SIZE; - enonce2 = continueflag2 - TPM_NONCE_SIZE; - - sdesc = init_sdesc(hashalg); - if (IS_ERR(sdesc)) { - pr_info("trusted_key: can't alloc %s\n", hash_alg); - return PTR_ERR(sdesc); - } - ret = crypto_shash_init(&sdesc->shash); - if (ret < 0) - goto out; - ret = crypto_shash_update(&sdesc->shash, (const u8 *)&result, - sizeof result); - if (ret < 0) - goto out; - ret = crypto_shash_update(&sdesc->shash, (const u8 *)&ordinal, - sizeof ordinal); - if (ret < 0) - goto out; - - va_start(argp, keylen2); - for (;;) { - dlen = va_arg(argp, unsigned int); - if (dlen == 0) - break; - dpos = va_arg(argp, unsigned int); - ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen); - if (ret < 0) - break; - } - va_end(argp); - if (!ret) - 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: - kfree(sdesc); - return ret; -} - -/* - * For key specific tpm requests, we will generate and send our - * own TPM command packets using the drivers send function. - */ -static int trusted_tpm_send(struct tpm_chip *chip, unsigned char *cmd, - size_t buflen, const char *desc) -{ - int rc; - - dump_tpm_buf(cmd); - rc = tpm_send_command(chip, cmd, buflen, desc); - dump_tpm_buf(cmd); - if (rc > 0) - /* Can't return positive return codes values to keyctl */ - rc = -EPERM; - return rc; -} - /* * Lock a trusted key, by extending a selected PCR. * @@ -387,281 +50,6 @@ static int pcrlock(struct tpm_chip *chip, const int pcrnum) return tpm_pcr_extend(chip, pcrnum, hash) ? -EINVAL : 0; } -/* - * Create an object specific authorisation protocol (OSAP) session - */ -static int osap(struct tpm_chip *chip, - struct tpm_buf *tb, struct osapsess *s, - const unsigned char *key, uint16_t type, uint32_t handle) -{ - unsigned char enonce[TPM_NONCE_SIZE]; - unsigned char ononce[TPM_NONCE_SIZE]; - int ret; - - ret = tpm_get_random(chip, ononce, TPM_NONCE_SIZE); - if (ret != TPM_NONCE_SIZE) - return ret; - - INIT_BUF(tb); - store16(tb, TPM_TAG_RQU_COMMAND); - store32(tb, TPM_OSAP_SIZE); - store32(tb, TPM_ORD_OSAP); - store16(tb, type); - store32(tb, handle); - storebytes(tb, ononce, TPM_NONCE_SIZE); - - ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE, - "creating OSAP session"); - if (ret < 0) - return ret; - - s->handle = LOAD32(tb->data, TPM_DATA_OFFSET); - memcpy(s->enonce, &(tb->data[TPM_DATA_OFFSET + sizeof(uint32_t)]), - TPM_NONCE_SIZE); - memcpy(enonce, &(tb->data[TPM_DATA_OFFSET + sizeof(uint32_t) + - TPM_NONCE_SIZE]), TPM_NONCE_SIZE); - return TSS_rawhmac(s->secret, key, SHA1_DIGEST_SIZE, TPM_NONCE_SIZE, - enonce, TPM_NONCE_SIZE, ononce, 0, 0); -} - -/* - * Create an object independent authorisation protocol (oiap) session - */ -static int oiap(struct tpm_chip *chip, struct tpm_buf *tb, uint32_t *handle, - unsigned char *nonce) -{ - int ret; - - INIT_BUF(tb); - store16(tb, TPM_TAG_RQU_COMMAND); - store32(tb, TPM_OIAP_SIZE); - store32(tb, TPM_ORD_OIAP); - ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE, - "creating OIAP session"); - if (ret < 0) - return ret; - - *handle = LOAD32(tb->data, TPM_DATA_OFFSET); - memcpy(nonce, &tb->data[TPM_DATA_OFFSET + sizeof(uint32_t)], - TPM_NONCE_SIZE); - return 0; -} - -struct tpm_digests { - unsigned char encauth[SHA1_DIGEST_SIZE]; - unsigned char pubauth[SHA1_DIGEST_SIZE]; - unsigned char xorwork[SHA1_DIGEST_SIZE * 2]; - unsigned char xorhash[SHA1_DIGEST_SIZE]; - unsigned char nonceodd[TPM_NONCE_SIZE]; -}; - -/* - * Have the TPM seal(encrypt) the trusted key, possibly based on - * Platform Configuration Registers (PCRs). AUTH1 for sealing key. - */ -static int tpm_seal(struct tpm_chip *chip, - struct tpm_buf *tb, uint16_t keytype, - uint32_t keyhandle, const unsigned char *keyauth, - const unsigned char *data, uint32_t datalen, - unsigned char *blob, uint32_t *bloblen, - const unsigned char *blobauth, - const unsigned char *pcrinfo, uint32_t pcrinfosize) -{ - struct osapsess sess; - struct tpm_digests *td; - unsigned char cont; - uint32_t ordinal; - uint32_t pcrsize; - uint32_t datsize; - int sealinfosize; - int encdatasize; - int storedsize; - int ret; - int i; - - /* alloc some work space for all the hashes */ - td = kmalloc(sizeof *td, GFP_KERNEL); - if (!td) - return -ENOMEM; - - /* get session for sealing key */ - ret = osap(chip, tb, &sess, keyauth, keytype, keyhandle); - if (ret < 0) - goto out; - dump_sess(&sess); - - /* calculate encrypted authorization value */ - memcpy(td->xorwork, sess.secret, SHA1_DIGEST_SIZE); - memcpy(td->xorwork + SHA1_DIGEST_SIZE, sess.enonce, SHA1_DIGEST_SIZE); - ret = TSS_sha1(td->xorwork, SHA1_DIGEST_SIZE * 2, td->xorhash); - if (ret < 0) - goto out; - - ret = tpm_get_random(chip, td->nonceodd, TPM_NONCE_SIZE); - if (ret != TPM_NONCE_SIZE) - goto out; - ordinal = htonl(TPM_ORD_SEAL); - datsize = htonl(datalen); - pcrsize = htonl(pcrinfosize); - cont = 0; - - /* encrypt data authorization key */ - for (i = 0; i < SHA1_DIGEST_SIZE; ++i) - td->encauth[i] = td->xorhash[i] ^ blobauth[i]; - - /* calculate authorization HMAC value */ - if (pcrinfosize == 0) { - /* no pcr info specified */ - 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 */ - 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) - goto out; - - /* build and send the TPM request packet */ - INIT_BUF(tb); - store16(tb, TPM_TAG_RQU_AUTH1_COMMAND); - store32(tb, TPM_SEAL_SIZE + pcrinfosize + datalen); - store32(tb, TPM_ORD_SEAL); - store32(tb, keyhandle); - storebytes(tb, td->encauth, SHA1_DIGEST_SIZE); - store32(tb, pcrinfosize); - storebytes(tb, pcrinfo, pcrinfosize); - store32(tb, datalen); - storebytes(tb, data, datalen); - store32(tb, sess.handle); - storebytes(tb, td->nonceodd, TPM_NONCE_SIZE); - store8(tb, cont); - storebytes(tb, td->pubauth, SHA1_DIGEST_SIZE); - - ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE, - "sealing data"); - if (ret < 0) - goto out; - - /* calculate the size of the returned Blob */ - 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; - - /* check the HMAC in the response */ - ret = TSS_checkhmac1(tb->data, ordinal, td->nonceodd, sess.secret, - SHA1_DIGEST_SIZE, storedsize, TPM_DATA_OFFSET, 0, - 0); - - /* copy the returned blob to caller */ - if (!ret) { - memcpy(blob, tb->data + TPM_DATA_OFFSET, storedsize); - *bloblen = storedsize; - } -out: - kfree(td); - return ret; -} - -/* - * use the AUTH2_COMMAND form of unseal, to authorize both key and blob - */ -static int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, - uint32_t keyhandle, const unsigned char *keyauth, - const unsigned char *blob, int bloblen, - const unsigned char *blobauth, - unsigned char *data, unsigned int *datalen) -{ - unsigned char nonceodd[TPM_NONCE_SIZE]; - unsigned char enonce1[TPM_NONCE_SIZE]; - unsigned char enonce2[TPM_NONCE_SIZE]; - unsigned char authdata1[SHA1_DIGEST_SIZE]; - unsigned char authdata2[SHA1_DIGEST_SIZE]; - uint32_t authhandle1 = 0; - uint32_t authhandle2 = 0; - unsigned char cont = 0; - uint32_t ordinal; - uint32_t keyhndl; - int ret; - - /* sessions for unsealing key and data */ - ret = oiap(chip, tb, &authhandle1, enonce1); - if (ret < 0) { - pr_info("trusted_key: oiap failed (%d)\n", ret); - return ret; - } - ret = oiap(chip, tb, &authhandle2, enonce2); - if (ret < 0) { - pr_info("trusted_key: oiap failed (%d)\n", ret); - return ret; - } - - ordinal = htonl(TPM_ORD_UNSEAL); - keyhndl = htonl(SRKHANDLE); - ret = tpm_get_random(chip, nonceodd, TPM_NONCE_SIZE); - if (ret != TPM_NONCE_SIZE) { - pr_info("trusted_key: tpm_get_random failed (%d)\n", ret); - return ret; - } - 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); - store16(tb, TPM_TAG_RQU_AUTH2_COMMAND); - store32(tb, TPM_UNSEAL_SIZE + bloblen); - store32(tb, TPM_ORD_UNSEAL); - store32(tb, keyhandle); - storebytes(tb, blob, bloblen); - store32(tb, authhandle1); - storebytes(tb, nonceodd, TPM_NONCE_SIZE); - store8(tb, cont); - storebytes(tb, authdata1, SHA1_DIGEST_SIZE); - store32(tb, authhandle2); - storebytes(tb, nonceodd, TPM_NONCE_SIZE); - store8(tb, cont); - storebytes(tb, authdata2, SHA1_DIGEST_SIZE); - - ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE, - "unsealing data"); - if (ret < 0) { - pr_info("trusted_key: authhmac failed (%d)\n", ret); - return ret; - } - - *datalen = LOAD32(tb->data, TPM_DATA_OFFSET); - ret = TSS_checkhmac2(tb->data, ordinal, nonceodd, - keyauth, SHA1_DIGEST_SIZE, - blobauth, SHA1_DIGEST_SIZE, - sizeof(uint32_t), TPM_DATA_OFFSET, - *datalen, TPM_DATA_OFFSET + sizeof(uint32_t), 0, - 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 0; -} - /* * Have the TPM seal(encrypt) the symmetric key */ @@ -1129,40 +517,6 @@ struct key_type key_type_trusted = { EXPORT_SYMBOL_GPL(key_type_trusted); -static void trusted_shash_release(void) -{ - if (hashalg) - crypto_free_shash(hashalg); - if (hmacalg) - crypto_free_shash(hmacalg); -} - -static int __init trusted_shash_alloc(void) -{ - int ret; - - hmacalg = crypto_alloc_shash(hmac_alg, 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(hmacalg)) { - pr_info("trusted_key: could not allocate crypto %s\n", - hmac_alg); - return PTR_ERR(hmacalg); - } - - hashalg = crypto_alloc_shash(hash_alg, 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(hashalg)) { - pr_info("trusted_key: could not allocate crypto %s\n", - hash_alg); - ret = PTR_ERR(hashalg); - goto hashalg_fail; - } - - return 0; - -hashalg_fail: - crypto_free_shash(hmacalg); - return ret; -} - static int __init init_trusted(void) { int ret; diff --git a/security/keys/trusted.h b/security/keys/trusted.h index 3249fbd2b653..61fe24d5c6b3 100644 --- a/security/keys/trusted.h +++ b/security/keys/trusted.h @@ -1,35 +1,6 @@ #ifndef __TRUSTED_KEY_H #define __TRUSTED_KEY_H -/* implementation specific TPM constants */ -#define MAX_PCRINFO_SIZE 64 -#define MAX_BUF_SIZE 512 -#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_SIZE_OFFSET 2 -#define TPM_RETURN_OFFSET 6 -#define TPM_DATA_OFFSET 10 - -#define LOAD32(buffer, offset) (ntohl(*(uint32_t *)&buffer[offset])) -#define LOAD32N(buffer, offset) (*(uint32_t *)&buffer[offset]) -#define LOAD16(buffer, offset) (ntohs(*(uint16_t *)&buffer[offset])) - -struct tpm_buf { - int len; - unsigned char data[MAX_BUF_SIZE]; -}; - -#define INIT_BUF(tb) (tb->len = 0) - -struct osapsess { - uint32_t handle; - unsigned char secret[SHA1_DIGEST_SIZE]; - unsigned char enonce[TPM_NONCE_SIZE]; -}; - /* discrete values, but have to store in uint16_t for TPM use */ enum { SEAL_keytype = 1, @@ -70,26 +41,6 @@ static inline void dump_payload(struct trusted_key_payload *p) pr_info("trusted_key: migratable %d\n", p->migratable); } -static inline void dump_sess(struct osapsess *s) -{ - print_hex_dump(KERN_INFO, "trusted-key: handle ", DUMP_PREFIX_NONE, - 16, 1, &s->handle, 4, 0); - pr_info("trusted-key: secret:\n"); - print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, - 16, 1, &s->secret, SHA1_DIGEST_SIZE, 0); - pr_info("trusted-key: enonce:\n"); - print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, - 16, 1, &s->enonce, SHA1_DIGEST_SIZE, 0); -} - -static inline void dump_tpm_buf(unsigned char *buf) -{ - int len; - - pr_info("\ntrusted-key: tpm buffer\n"); - len = LOAD32(buf, TPM_SIZE_OFFSET); - print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, buf, len, 0); -} #else static inline void dump_options(struct trusted_key_options *o) { @@ -99,36 +50,5 @@ static inline void dump_payload(struct trusted_key_payload *p) { } -static inline void dump_sess(struct osapsess *s) -{ -} - -static inline void dump_tpm_buf(unsigned char *buf) -{ -} #endif - -static inline void store8(struct tpm_buf *buf, const unsigned char value) -{ - buf->data[buf->len++] = value; -} - -static inline void store16(struct tpm_buf *buf, const uint16_t value) -{ - *(uint16_t *) & buf->data[buf->len] = htons(value); - buf->len += sizeof value; -} - -static inline void store32(struct tpm_buf *buf, const uint32_t value) -{ - *(uint32_t *) & buf->data[buf->len] = htonl(value); - buf->len += sizeof value; -} - -static inline void storebytes(struct tpm_buf *buf, const unsigned char *in, - const int len) -{ - memcpy(buf->data + buf->len, in, len); - buf->len += len; -} #endif From patchwork Tue Aug 21 15:57:50 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 10571949 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C9A5A921 for ; Tue, 21 Aug 2018 15:57:55 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B7D7227C2D for ; Tue, 21 Aug 2018 15:57:55 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id AB8382A4E0; Tue, 21 Aug 2018 15:57:55 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id EEBB127C2D for ; Tue, 21 Aug 2018 15:57:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728122AbeHUTSf (ORCPT ); Tue, 21 Aug 2018 15:18:35 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:43484 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726967AbeHUTSe (ORCPT ); Tue, 21 Aug 2018 15:18:34 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id BBCF640216E8; Tue, 21 Aug 2018 15:57:51 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-123-147.rdu2.redhat.com [10.10.123.147]) by smtp.corp.redhat.com (Postfix) with ESMTP id 934A52166BA1; Tue, 21 Aug 2018 15:57:50 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 09/23] TPMLIB: Do some source cleanups From: David Howells To: denkenz@gmail.com, jarkko.sakkinen@linux.intel.com, jejb@linux.vnet.ibm.com Cc: keyrings@vger.kernel.org, linux-integrity@vger.kernel.org, tpmdd-devel@lists.sourceforge.net, linux-security-module@vger.kernel.org Date: Tue, 21 Aug 2018 16:57:50 +0100 Message-ID: <153486707011.13066.14435967283392358361.stgit@warthog.procyon.org.uk> In-Reply-To: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> References: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Tue, 21 Aug 2018 15:57:51 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Tue, 21 Aug 2018 15:57:51 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'dhowells@redhat.com' RCPT:'' Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Clean up the TPM library file that was split out of trusted keys. Signed-off-by: David Howells --- drivers/char/tpm/tpm-library.c | 187 +++++++++++++++++++++++----------------- drivers/char/tpm/tpm-library.h | 14 +-- include/linux/tpm.h | 4 - security/keys/trusted.c | 6 + 4 files changed, 121 insertions(+), 90 deletions(-) diff --git a/drivers/char/tpm/tpm-library.c b/drivers/char/tpm/tpm-library.c index 1be4f71cabcb..e4cfc1f090e1 100644 --- a/drivers/char/tpm/tpm-library.c +++ b/drivers/char/tpm/tpm-library.c @@ -8,44 +8,36 @@ * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 2 of the License. - * - * See Documentation/security/keys-trusted-encrypted.txt */ -#include -#include -#include +#define pr_fmt(fmt) "TPMLIB: "fmt #include -#include -#include #include -#include -#include -#include -#include +#include #include #include #include -#include #include #include #include "tpm-library.h" -static const char hmac_alg[] = "hmac(sha1)"; -static const char hash_alg[] = "sha1"; +static const char tpm_hmac_alg[] = "hmac(sha1)"; +static const char tpm_hash_alg[] = "sha1"; -struct sdesc { +struct tpm_sdesc { struct shash_desc shash; char ctx[]; }; -static struct crypto_shash *hashalg; -static struct crypto_shash *hmacalg; +static DEFINE_MUTEX(tpm_library_init_mutex); +static atomic_t tpm_library_usage; +static struct crypto_shash *tpm_hashalg; +static struct crypto_shash *tpm_hmacalg; -static struct sdesc *init_sdesc(struct crypto_shash *alg) +static struct tpm_sdesc *tpm_init_sdesc(struct crypto_shash *alg) { - struct sdesc *sdesc; + struct tpm_sdesc *sdesc; int size; size = sizeof(struct shash_desc) + crypto_shash_descsize(alg); @@ -60,12 +52,12 @@ static struct sdesc *init_sdesc(struct crypto_shash *alg) static int TSS_sha1(const unsigned char *data, unsigned int datalen, unsigned char *digest) { - struct sdesc *sdesc; + struct tpm_sdesc *sdesc; int ret; - sdesc = init_sdesc(hashalg); + sdesc = tpm_init_sdesc(tpm_hashalg); if (IS_ERR(sdesc)) { - pr_info("trusted_key: can't alloc %s\n", hash_alg); + pr_info("Can't alloc %s\n", tpm_hash_alg); return PTR_ERR(sdesc); } @@ -77,19 +69,19 @@ static int TSS_sha1(const unsigned char *data, unsigned int datalen, static int TSS_rawhmac(unsigned char *digest, const unsigned char *key, unsigned int keylen, ...) { - struct sdesc *sdesc; + struct tpm_sdesc *sdesc; va_list argp; unsigned int dlen; unsigned char *data; int ret; - sdesc = init_sdesc(hmacalg); + sdesc = tpm_init_sdesc(tpm_hmacalg); if (IS_ERR(sdesc)) { - pr_info("trusted_key: can't alloc %s\n", hmac_alg); + pr_info("Can't alloc %s\n", tpm_hmac_alg); return PTR_ERR(sdesc); } - ret = crypto_shash_setkey(hmacalg, key, keylen); + ret = crypto_shash_setkey(tpm_hmacalg, key, keylen); if (ret < 0) goto out; ret = crypto_shash_init(&sdesc->shash); @@ -126,16 +118,16 @@ static int TSS_authhmac(unsigned char *digest, const unsigned char *key, unsigned char *h2, unsigned char h3, ...) { unsigned char paramdigest[SHA1_DIGEST_SIZE]; - struct sdesc *sdesc; + struct tpm_sdesc *sdesc; unsigned int dlen; unsigned char *data; unsigned char c; int ret; va_list argp; - sdesc = init_sdesc(hashalg); + sdesc = tpm_init_sdesc(tpm_hashalg); if (IS_ERR(sdesc)) { - pr_info("trusted_key: can't alloc %s\n", hash_alg); + pr_info("Can't alloc %s\n", tpm_hash_alg); return PTR_ERR(sdesc); } @@ -187,7 +179,7 @@ static int TSS_checkhmac1(unsigned char *buffer, unsigned char *authdata; unsigned char testhmac[SHA1_DIGEST_SIZE]; unsigned char paramdigest[SHA1_DIGEST_SIZE]; - struct sdesc *sdesc; + struct tpm_sdesc *sdesc; unsigned int dlen; unsigned int dpos; va_list argp; @@ -205,9 +197,9 @@ static int TSS_checkhmac1(unsigned char *buffer, continueflag = authdata - 1; enonce = continueflag - TPM_NONCE_SIZE; - sdesc = init_sdesc(hashalg); + sdesc = tpm_init_sdesc(tpm_hashalg); if (IS_ERR(sdesc)) { - pr_info("trusted_key: can't alloc %s\n", hash_alg); + pr_info("Can't alloc %s\n", tpm_hash_alg); return PTR_ERR(sdesc); } ret = crypto_shash_init(&sdesc->shash); @@ -274,7 +266,7 @@ static int TSS_checkhmac2(unsigned char *buffer, unsigned char testhmac1[SHA1_DIGEST_SIZE]; unsigned char testhmac2[SHA1_DIGEST_SIZE]; unsigned char paramdigest[SHA1_DIGEST_SIZE]; - struct sdesc *sdesc; + struct tpm_sdesc *sdesc; unsigned int dlen; unsigned int dpos; va_list argp; @@ -297,9 +289,9 @@ static int TSS_checkhmac2(unsigned char *buffer, enonce1 = continueflag1 - TPM_NONCE_SIZE; enonce2 = continueflag2 - TPM_NONCE_SIZE; - sdesc = init_sdesc(hashalg); + sdesc = tpm_init_sdesc(tpm_hashalg); if (IS_ERR(sdesc)) { - pr_info("trusted_key: can't alloc %s\n", hash_alg); + pr_info("Can't alloc %s\n", tpm_hash_alg); return PTR_ERR(sdesc); } ret = crypto_shash_init(&sdesc->shash); @@ -355,8 +347,8 @@ out: * For key specific tpm requests, we will generate and send our * own TPM command packets using the drivers send function. */ -static int trusted_tpm_send(struct tpm_chip *chip, unsigned char *cmd, - size_t buflen, const char *desc) +static int tpm_send_dump(struct tpm_chip *chip, + unsigned char *cmd, size_t buflen, const char *desc) { int rc; @@ -372,9 +364,10 @@ static int trusted_tpm_send(struct tpm_chip *chip, unsigned char *cmd, /* * Create an object specific authorisation protocol (OSAP) session */ -static int osap(struct tpm_chip *chip, - struct tpm_buf *tb, struct osapsess *s, - const unsigned char *key, uint16_t type, uint32_t handle) +static int tpm_create_osap(struct tpm_chip *chip, + struct tpm_buf *tb, struct tpm_osapsess *s, + const unsigned char *key, uint16_t type, + uint32_t handle) { unsigned char enonce[TPM_NONCE_SIZE]; unsigned char ononce[TPM_NONCE_SIZE]; @@ -392,8 +385,8 @@ static int osap(struct tpm_chip *chip, store32(tb, handle); storebytes(tb, ononce, TPM_NONCE_SIZE); - ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE, - "creating OSAP session"); + ret = tpm_send_dump(chip, tb->data, MAX_BUF_SIZE, + "creating OSAP session"); if (ret < 0) return ret; @@ -409,8 +402,8 @@ static int osap(struct tpm_chip *chip, /* * Create an object independent authorisation protocol (oiap) session */ -static int oiap(struct tpm_chip *chip, struct tpm_buf *tb, uint32_t *handle, - unsigned char *nonce) +static int tpm_create_oiap(struct tpm_chip *chip, struct tpm_buf *tb, + uint32_t *handle, unsigned char *nonce) { int ret; @@ -418,8 +411,8 @@ static int oiap(struct tpm_chip *chip, struct tpm_buf *tb, uint32_t *handle, store16(tb, TPM_TAG_RQU_COMMAND); store32(tb, TPM_OIAP_SIZE); store32(tb, TPM_ORD_OIAP); - ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE, - "creating OIAP session"); + ret = tpm_send_dump(chip, tb->data, MAX_BUF_SIZE, + "creating OIAP session"); if (ret < 0) return ret; @@ -448,7 +441,7 @@ int tpm_seal(struct tpm_chip *chip, struct tpm_buf *tb, uint16_t keytype, const unsigned char *blobauth, const unsigned char *pcrinfo, uint32_t pcrinfosize) { - struct osapsess sess; + struct tpm_osapsess sess; struct tpm_digests *td; unsigned char cont; uint32_t ordinal; @@ -466,7 +459,7 @@ int tpm_seal(struct tpm_chip *chip, struct tpm_buf *tb, uint16_t keytype, return -ENOMEM; /* get session for sealing key */ - ret = osap(chip, tb, &sess, keyauth, keytype, keyhandle); + ret = tpm_create_osap(chip, tb, &sess, keyauth, keytype, keyhandle); if (ret < 0) goto out; dump_sess(&sess); @@ -527,8 +520,8 @@ int tpm_seal(struct tpm_chip *chip, struct tpm_buf *tb, uint16_t keytype, store8(tb, cont); storebytes(tb, td->pubauth, SHA1_DIGEST_SIZE); - ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE, - "sealing data"); + ret = tpm_send_dump(chip, tb->data, MAX_BUF_SIZE, + "sealing data"); if (ret < 0) goto out; @@ -577,14 +570,14 @@ int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, int ret; /* sessions for unsealing key and data */ - ret = oiap(chip, tb, &authhandle1, enonce1); + ret = tpm_create_oiap(chip, tb, &authhandle1, enonce1); if (ret < 0) { - pr_info("trusted_key: oiap failed (%d)\n", ret); + pr_info("Failed to create OIAP 1 (%d)\n", ret); return ret; } - ret = oiap(chip, tb, &authhandle2, enonce2); + ret = tpm_create_oiap(chip, tb, &authhandle2, enonce2); if (ret < 0) { - pr_info("trusted_key: oiap failed (%d)\n", ret); + pr_info("Failed to create OIAP 2 (%d)\n", ret); return ret; } @@ -592,7 +585,7 @@ int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, keyhndl = htonl(SRKHANDLE); ret = tpm_get_random(chip, nonceodd, TPM_NONCE_SIZE); if (ret != TPM_NONCE_SIZE) { - pr_info("trusted_key: tpm_get_random failed (%d)\n", ret); + pr_info("tpm_get_random failed (%d)\n", ret); return ret; } ret = TSS_authhmac(authdata1, keyauth, TPM_NONCE_SIZE, @@ -622,10 +615,10 @@ int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, store8(tb, cont); storebytes(tb, authdata2, SHA1_DIGEST_SIZE); - ret = trusted_tpm_send(chip, tb->data, MAX_BUF_SIZE, - "unsealing data"); + ret = tpm_send_dump(chip, tb->data, MAX_BUF_SIZE, + "unsealing data"); if (ret < 0) { - pr_info("trusted_key: authhmac failed (%d)\n", ret); + pr_info("authhmac failed (%d)\n", ret); return ret; } @@ -637,7 +630,7 @@ int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, *datalen, TPM_DATA_OFFSET + sizeof(uint32_t), 0, 0); if (ret < 0) { - pr_info("trusted_key: TSS_checkhmac2 failed (%d)\n", ret); + pr_info("TSS_checkhmac2 failed (%d)\n", ret); return ret; } memcpy(data, tb->data + TPM_DATA_OFFSET + sizeof(uint32_t), *datalen); @@ -645,38 +638,76 @@ int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, } EXPORT_SYMBOL_GPL(tpm_unseal); -void trusted_shash_release(void) -{ - if (hashalg) - crypto_free_shash(hashalg); - if (hmacalg) - crypto_free_shash(hmacalg); -} -EXPORT_SYMBOL_GPL(trusted_shash_release); - -int trusted_shash_alloc(void) +/** + * tpm_library_use - Tell the TPM library we want to make use of it + * + * Tell the TPM library that we want to make use of it, allowing it to + * allocate the resources it needs. + */ +int tpm_library_use(void) { + struct crypto_shash *hashalg = NULL; + struct crypto_shash *hmacalg = NULL; int ret; - hmacalg = crypto_alloc_shash(hmac_alg, 0, CRYPTO_ALG_ASYNC); + if (atomic_inc_not_zero(&tpm_library_usage)) + return 0; + + /* We don't want to hold a mutex whilst allocating a crypto + * object as it may have to call up to userspace. + */ + hmacalg = crypto_alloc_shash(tpm_hmac_alg, 0, CRYPTO_ALG_ASYNC); if (IS_ERR(hmacalg)) { - pr_info("trusted_key: could not allocate crypto %s\n", - hmac_alg); - return PTR_ERR(hmacalg); + pr_info("Could not allocate crypto %s\n", tpm_hmac_alg); + ret = PTR_ERR(hmacalg); + goto hmacalg_fail; } - hashalg = crypto_alloc_shash(hash_alg, 0, CRYPTO_ALG_ASYNC); + hashalg = crypto_alloc_shash(tpm_hash_alg, 0, CRYPTO_ALG_ASYNC); if (IS_ERR(hashalg)) { - pr_info("trusted_key: could not allocate crypto %s\n", - hash_alg); + pr_info("Could not allocate crypto %s\n", tpm_hash_alg); ret = PTR_ERR(hashalg); goto hashalg_fail; } + mutex_lock(&tpm_library_init_mutex); + + if (atomic_inc_return(&tpm_library_usage) == 1) { + tpm_hmacalg = hmacalg; + tpm_hashalg = hashalg; + } else { + crypto_free_shash(hashalg); + crypto_free_shash(hmacalg); + } + + mutex_unlock(&tpm_library_init_mutex); return 0; hashalg_fail: - crypto_free_shash(hmacalg); + crypto_free_shash(tpm_hmacalg); +hmacalg_fail: return ret; } -EXPORT_SYMBOL_GPL(trusted_shash_alloc); +EXPORT_SYMBOL_GPL(tpm_library_use); + +/** + * tpm_library_unuse - Tell the TPM library we've finished with it + * + * Tell the TPM library we've finished with it, allowing it to free the + * resources it had allocated. + */ +void tpm_library_unuse(void) +{ + if (atomic_add_unless(&tpm_library_usage, -1, 1)) + return; + + mutex_lock(&tpm_library_init_mutex); + + if (atomic_dec_and_test(&tpm_library_usage)) { + crypto_free_shash(tpm_hashalg); + crypto_free_shash(tpm_hmacalg); + } + + mutex_unlock(&tpm_library_init_mutex); +} +EXPORT_SYMBOL_GPL(tpm_library_unuse); diff --git a/drivers/char/tpm/tpm-library.h b/drivers/char/tpm/tpm-library.h index eec1dfe26c2a..6f7571cc6d6c 100644 --- a/drivers/char/tpm/tpm-library.h +++ b/drivers/char/tpm/tpm-library.h @@ -15,7 +15,7 @@ #define LOAD32N(buffer, offset) (*(uint32_t *)&buffer[offset]) #define LOAD16(buffer, offset) (ntohs(*(uint16_t *)&buffer[offset])) -struct osapsess { +struct tpm_osapsess { uint32_t handle; unsigned char secret[SHA1_DIGEST_SIZE]; unsigned char enonce[TPM_NONCE_SIZE]; @@ -51,14 +51,14 @@ static inline void storebytes(struct tpm_buf *buf, const unsigned char *in, #define TPM_DEBUG 0 #ifdef TPM_DEBUG -static inline void dump_sess(struct osapsess *s) +static inline void dump_sess(struct tpm_osapsess *s) { - print_hex_dump(KERN_INFO, "trusted-key: handle ", DUMP_PREFIX_NONE, + print_hex_dump(KERN_INFO, "handle ", DUMP_PREFIX_NONE, 16, 1, &s->handle, 4, 0); - pr_info("trusted-key: secret:\n"); + pr_info("secret:\n"); print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, &s->secret, SHA1_DIGEST_SIZE, 0); - pr_info("trusted-key: enonce:\n"); + pr_info("enonce:\n"); print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, &s->enonce, SHA1_DIGEST_SIZE, 0); } @@ -67,13 +67,13 @@ static inline void dump_tpm_buf(unsigned char *buf) { int len; - pr_info("\ntrusted-key: tpm buffer\n"); + pr_info("\ntpm buffer\n"); len = LOAD32(buf, TPM_SIZE_OFFSET); print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, buf, len, 0); } #else -static inline void dump_sess(struct osapsess *s) +static inline void dump_sess(struct tpm_osapsess *s) { } diff --git a/include/linux/tpm.h b/include/linux/tpm.h index 5d8caf56c272..b08539920f76 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -100,8 +100,8 @@ struct tpm_buf { #define INIT_BUF(tb) (tb->len = 0) -extern void trusted_shash_release(void); -extern int trusted_shash_alloc(void); +extern int tpm_library_use(void); +extern void tpm_library_unuse(void); extern int tpm_seal(struct tpm_chip *chip, struct tpm_buf *tb, uint16_t keytype, uint32_t keyhandle, const unsigned char *keyauth, diff --git a/security/keys/trusted.c b/security/keys/trusted.c index 83c6a485e62a..3afb152a6ae2 100644 --- a/security/keys/trusted.c +++ b/security/keys/trusted.c @@ -521,19 +521,19 @@ static int __init init_trusted(void) { int ret; - ret = trusted_shash_alloc(); + ret = tpm_library_use(); if (ret < 0) return ret; ret = register_key_type(&key_type_trusted); if (ret < 0) - trusted_shash_release(); + tpm_library_unuse(); return ret; } static void __exit cleanup_trusted(void) { - trusted_shash_release(); unregister_key_type(&key_type_trusted); + tpm_library_unuse(); } late_initcall(init_trusted); From patchwork Tue Aug 21 15:57:56 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 10571953 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7ECD41390 for ; Tue, 21 Aug 2018 15:58:02 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6A76B27C2D for ; Tue, 21 Aug 2018 15:58:02 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 5EA0929046; Tue, 21 Aug 2018 15:58:02 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BBCDE2A4F2 for ; Tue, 21 Aug 2018 15:58:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728128AbeHUTSl (ORCPT ); Tue, 21 Aug 2018 15:18:41 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:45132 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726967AbeHUTSl (ORCPT ); Tue, 21 Aug 2018 15:18:41 -0400 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 687ED402178A; Tue, 21 Aug 2018 15:57:58 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-123-147.rdu2.redhat.com [10.10.123.147]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5E59B9464B; Tue, 21 Aug 2018 15:57:57 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 10/23] TPMLIB: Better format calls to TSS_*hmac*() From: David Howells To: denkenz@gmail.com, jarkko.sakkinen@linux.intel.com, jejb@linux.vnet.ibm.com Cc: keyrings@vger.kernel.org, linux-integrity@vger.kernel.org, tpmdd-devel@lists.sourceforge.net, linux-security-module@vger.kernel.org Date: Tue, 21 Aug 2018 16:57:56 +0100 Message-ID: <153486707690.13066.12378140282590781364.stgit@warthog.procyon.org.uk> In-Reply-To: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> References: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Tue, 21 Aug 2018 15:57:58 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Tue, 21 Aug 2018 15:57:58 +0000 (UTC) for IP:'10.11.54.5' DOMAIN:'int-mx05.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'dhowells@redhat.com' RCPT:'' Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Better format calls to TSS_rawhmac(), TSS_authhmac() and TSS_checkhmac*(). Each of these calls takes a varargs list of pairs of datasize and data values. Put each pair on its own line so that things are more obvious. Signed-off-by: David Howells --- drivers/char/tpm/tpm-library.c | 86 ++++++++++++++++++++++++++-------------- 1 file changed, 55 insertions(+), 31 deletions(-) diff --git a/drivers/char/tpm/tpm-library.c b/drivers/char/tpm/tpm-library.c index e4cfc1f090e1..41fe4247a4c8 100644 --- a/drivers/char/tpm/tpm-library.c +++ b/drivers/char/tpm/tpm-library.c @@ -153,9 +153,12 @@ static int TSS_authhmac(unsigned char *digest, const unsigned char *key, if (!ret) ret = crypto_shash_final(&sdesc->shash, paramdigest); if (!ret) - 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; @@ -229,9 +232,12 @@ static int TSS_checkhmac1(unsigned char *buffer, 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); + 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; @@ -322,18 +328,24 @@ static int TSS_checkhmac2(unsigned char *buffer, 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); + 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); + 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)) @@ -395,8 +407,10 @@ static int tpm_create_osap(struct tpm_chip *chip, TPM_NONCE_SIZE); memcpy(enonce, &(tb->data[TPM_DATA_OFFSET + sizeof(uint32_t) + TPM_NONCE_SIZE]), TPM_NONCE_SIZE); - return TSS_rawhmac(s->secret, key, SHA1_DIGEST_SIZE, TPM_NONCE_SIZE, - enonce, TPM_NONCE_SIZE, ononce, 0, 0); + return TSS_rawhmac(s->secret, key, SHA1_DIGEST_SIZE, + TPM_NONCE_SIZE, enonce, + TPM_NONCE_SIZE, ononce, + 0, 0); } /* @@ -488,18 +502,23 @@ int tpm_seal(struct tpm_chip *chip, struct tpm_buf *tb, uint16_t keytype, /* no pcr info specified */ 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); + 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 */ 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); + 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) goto out; @@ -533,9 +552,10 @@ int tpm_seal(struct tpm_chip *chip, struct tpm_buf *tb, uint16_t keytype, sizeof(uint32_t) + encdatasize; /* check the HMAC in the response */ - ret = TSS_checkhmac1(tb->data, ordinal, td->nonceodd, sess.secret, - SHA1_DIGEST_SIZE, storedsize, TPM_DATA_OFFSET, 0, - 0); + ret = TSS_checkhmac1(tb->data, ordinal, td->nonceodd, + sess.secret, SHA1_DIGEST_SIZE, + storedsize, TPM_DATA_OFFSET, + 0, 0); /* copy the returned blob to caller */ if (!ret) { @@ -589,13 +609,17 @@ int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, return ret; } ret = TSS_authhmac(authdata1, keyauth, TPM_NONCE_SIZE, - enonce1, nonceodd, cont, sizeof(uint32_t), - &ordinal, bloblen, blob, 0, 0); + 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); + enonce2, nonceodd, cont, + sizeof(uint32_t), &ordinal, + bloblen, blob, + 0, 0); if (ret < 0) return ret; @@ -627,8 +651,8 @@ int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, keyauth, SHA1_DIGEST_SIZE, blobauth, SHA1_DIGEST_SIZE, sizeof(uint32_t), TPM_DATA_OFFSET, - *datalen, TPM_DATA_OFFSET + sizeof(uint32_t), 0, - 0); + *datalen, TPM_DATA_OFFSET + sizeof(uint32_t), + 0, 0); if (ret < 0) { pr_info("TSS_checkhmac2 failed (%d)\n", ret); return ret; From patchwork Tue Aug 21 15:58:03 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 10571957 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2DD3217E0 for ; Tue, 21 Aug 2018 15:58:09 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1DD5A2A51D for ; Tue, 21 Aug 2018 15:58:09 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1179F2A527; Tue, 21 Aug 2018 15:58:09 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5A6E12A51E for ; Tue, 21 Aug 2018 15:58:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728132AbeHUTSt (ORCPT ); Tue, 21 Aug 2018 15:18:49 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:54764 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726967AbeHUTSt (ORCPT ); Tue, 21 Aug 2018 15:18:49 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 315F67DAC9; Tue, 21 Aug 2018 15:58:05 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-123-147.rdu2.redhat.com [10.10.123.147]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0D3DF10CD65A; Tue, 21 Aug 2018 15:58:03 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 11/23] TPMLIB: Put banner comments on public TPM library functions From: David Howells To: denkenz@gmail.com, jarkko.sakkinen@linux.intel.com, jejb@linux.vnet.ibm.com Cc: keyrings@vger.kernel.org, linux-integrity@vger.kernel.org, tpmdd-devel@lists.sourceforge.net, linux-security-module@vger.kernel.org Date: Tue, 21 Aug 2018 16:58:03 +0100 Message-ID: <153486708356.13066.15616902542019684189.stgit@warthog.procyon.org.uk> In-Reply-To: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> References: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Tue, 21 Aug 2018 15:58:05 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Tue, 21 Aug 2018 15:58:05 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'dhowells@redhat.com' RCPT:'' Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Put banner comments on public TPM library functions and, if necessary, rename the arguments to make them more obvious. Signed-off-by: David Howells --- drivers/char/tpm/tpm-library.c | 126 ++++++++++++++++++++++++++++------------ include/linux/tpm.h | 19 ++++++ 2 files changed, 105 insertions(+), 40 deletions(-) diff --git a/drivers/char/tpm/tpm-library.c b/drivers/char/tpm/tpm-library.c index 41fe4247a4c8..7d1f55413f02 100644 --- a/drivers/char/tpm/tpm-library.c +++ b/drivers/char/tpm/tpm-library.c @@ -66,8 +66,17 @@ static int TSS_sha1(const unsigned char *data, unsigned int datalen, return ret; } -static int TSS_rawhmac(unsigned char *digest, const unsigned char *key, - unsigned int keylen, ...) +/** + * TSS_rawhmac - Generate a HMAC(SHA1) from raw data + * @digest: Result buffer - must be SHA1_DIGEST_SIZE in size + * @key: The key to use in the HMAC generation + * @keylen: The size of @key + * @...: Pairs of size and pointer of data elements to load into hmac + * @0,0: Terminator + */ +static int TSS_rawhmac(unsigned char *digest, + const unsigned char *key, unsigned keylen, + ...) { struct tpm_sdesc *sdesc; va_list argp; @@ -110,7 +119,17 @@ out: return ret; } -/* +/** + * TSS_authhmac - Calculate authorisation info to send to TPM + * @digest: Result buffer - must be SHA1_DIGEST_SIZE in size + * @key: The key to use in the HMAC generation + * @keylen: The size of @key + * @h1: Even nonce + * @h2: Odd nonce + * @h3: Continuation flag + * @...: Pairs of size and pointer of data elements to load into hash + * @0,0: Terminator + * * calculate authorization info fields to send to TPM */ static int TSS_authhmac(unsigned char *digest, const unsigned char *key, @@ -378,8 +397,8 @@ static int tpm_send_dump(struct tpm_chip *chip, */ static int tpm_create_osap(struct tpm_chip *chip, struct tpm_buf *tb, struct tpm_osapsess *s, - const unsigned char *key, uint16_t type, - uint32_t handle) + const unsigned char *keyauth, + enum tpm_entity_type keytype, uint32_t keyhandle) { unsigned char enonce[TPM_NONCE_SIZE]; unsigned char ononce[TPM_NONCE_SIZE]; @@ -393,8 +412,8 @@ static int tpm_create_osap(struct tpm_chip *chip, store16(tb, TPM_TAG_RQU_COMMAND); store32(tb, TPM_OSAP_SIZE); store32(tb, TPM_ORD_OSAP); - store16(tb, type); - store32(tb, handle); + store16(tb, keytype); + store32(tb, keyhandle); storebytes(tb, ononce, TPM_NONCE_SIZE); ret = tpm_send_dump(chip, tb->data, MAX_BUF_SIZE, @@ -407,7 +426,7 @@ static int tpm_create_osap(struct tpm_chip *chip, TPM_NONCE_SIZE); memcpy(enonce, &(tb->data[TPM_DATA_OFFSET + sizeof(uint32_t) + TPM_NONCE_SIZE]), TPM_NONCE_SIZE); - return TSS_rawhmac(s->secret, key, SHA1_DIGEST_SIZE, + return TSS_rawhmac(s->secret, keyauth, SHA1_DIGEST_SIZE, TPM_NONCE_SIZE, enonce, TPM_NONCE_SIZE, ononce, 0, 0); @@ -444,15 +463,33 @@ struct tpm_digests { unsigned char nonceodd[TPM_NONCE_SIZE]; }; -/* - * Have the TPM seal(encrypt) the trusted key, possibly based on - * Platform Configuration Registers (PCRs). AUTH1 for sealing key. +/** + * tpm_seal - Encrypt one key according to another plus PCR state + * @chip: The chip to use + * @tb: Large scratch buffer for I/O + * @keytype: Type of entity attached to @keyhandle + * @keyhandle: TPM-resident key used to encrypt + * @keyauth: 'Password' to use the key. + * @rawdata: Data to be encrypted + * @rawlen: Length of @rawdata + * @encbuffer: Buffer to hold the encrypted data (max SHA1_DIGEST_SIZE) + * @_enclen: Where to place the size of the encrypted data + * @encauth: 'Password' to use to encrypt authorisation key + * @pcrinfo: Information on PCR register values to seal to + * @pcrinfosize: size of @pcrinfo + * + * Have the TPM seal (encrypt) the data in the data buffer. The encryption is + * based on a key already resident in the TPM and may also include the state of + * one or more Platform Configuration Registers (PCRs). + * + * AUTH1 is used for sealing key. */ -int tpm_seal(struct tpm_chip *chip, struct tpm_buf *tb, uint16_t keytype, +int tpm_seal(struct tpm_chip *chip, + struct tpm_buf *tb, enum tpm_entity_type keytype, uint32_t keyhandle, const unsigned char *keyauth, - const unsigned char *data, uint32_t datalen, - unsigned char *blob, uint32_t *bloblen, - const unsigned char *blobauth, + const unsigned char *rawdata, uint32_t rawlen, + unsigned char *encbuffer, uint32_t *_enclen, + const unsigned char *encauth, const unsigned char *pcrinfo, uint32_t pcrinfosize) { struct tpm_osapsess sess; @@ -489,13 +526,13 @@ int tpm_seal(struct tpm_chip *chip, struct tpm_buf *tb, uint16_t keytype, if (ret != TPM_NONCE_SIZE) goto out; ordinal = htonl(TPM_ORD_SEAL); - datsize = htonl(datalen); + datsize = htonl(rawlen); pcrsize = htonl(pcrinfosize); cont = 0; /* encrypt data authorization key */ for (i = 0; i < SHA1_DIGEST_SIZE; ++i) - td->encauth[i] = td->xorhash[i] ^ blobauth[i]; + td->encauth[i] = td->xorhash[i] ^ encauth[i]; /* calculate authorization HMAC value */ if (pcrinfosize == 0) { @@ -506,7 +543,7 @@ int tpm_seal(struct tpm_chip *chip, struct tpm_buf *tb, uint16_t keytype, SHA1_DIGEST_SIZE, td->encauth, sizeof(uint32_t), &pcrsize, sizeof(uint32_t), &datsize, - datalen, data, + rawlen, rawdata, 0, 0); } else { /* pcr info specified */ @@ -517,7 +554,7 @@ int tpm_seal(struct tpm_chip *chip, struct tpm_buf *tb, uint16_t keytype, sizeof(uint32_t), &pcrsize, pcrinfosize, pcrinfo, sizeof(uint32_t), &datsize, - datalen, data, + rawlen, rawdata, 0, 0); } if (ret < 0) @@ -526,14 +563,14 @@ int tpm_seal(struct tpm_chip *chip, struct tpm_buf *tb, uint16_t keytype, /* build and send the TPM request packet */ INIT_BUF(tb); store16(tb, TPM_TAG_RQU_AUTH1_COMMAND); - store32(tb, TPM_SEAL_SIZE + pcrinfosize + datalen); + store32(tb, TPM_SEAL_SIZE + pcrinfosize + rawlen); store32(tb, TPM_ORD_SEAL); store32(tb, keyhandle); storebytes(tb, td->encauth, SHA1_DIGEST_SIZE); store32(tb, pcrinfosize); storebytes(tb, pcrinfo, pcrinfosize); - store32(tb, datalen); - storebytes(tb, data, datalen); + store32(tb, rawlen); + storebytes(tb, rawdata, rawlen); store32(tb, sess.handle); storebytes(tb, td->nonceodd, TPM_NONCE_SIZE); store8(tb, cont); @@ -544,7 +581,7 @@ int tpm_seal(struct tpm_chip *chip, struct tpm_buf *tb, uint16_t keytype, if (ret < 0) goto out; - /* calculate the size of the returned Blob */ + /* 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); @@ -557,10 +594,10 @@ int tpm_seal(struct tpm_chip *chip, struct tpm_buf *tb, uint16_t keytype, storedsize, TPM_DATA_OFFSET, 0, 0); - /* copy the returned blob to caller */ + /* copy the encrypted data to caller's buffer */ if (!ret) { - memcpy(blob, tb->data + TPM_DATA_OFFSET, storedsize); - *bloblen = storedsize; + memcpy(encbuffer, tb->data + TPM_DATA_OFFSET, storedsize); + *_enclen = storedsize; } out: kfree(td); @@ -568,14 +605,25 @@ out: } EXPORT_SYMBOL_GPL(tpm_seal); -/* +/** + * tpm_unseal - Encrypt one key according to another plus PCR state + * @chip: The chip to use + * @tb: Large scratch buffer for I/O + * @keyhandle: TPM-resident key used to decrypt + * @keyauth: HMAC key + * @encdata: Data to be decrypted + * @enclen: Length of @encdata + * @decauth: Data to use to decrypt the authorisation key + * @rawbuffer: Buffer to hold the decrypted data (max SHA1_DIGEST_SIZE) + * @_rawlen: Where to place the size of the decrypted data + * * use the AUTH2_COMMAND form of unseal, to authorize both key and blob */ int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, uint32_t keyhandle, const unsigned char *keyauth, - const unsigned char *blob, int bloblen, - const unsigned char *blobauth, - unsigned char *data, unsigned int *datalen) + const unsigned char *encdata, int enclen, + const unsigned char *decauth, + unsigned char *rawbuffer, unsigned int *_rawlen) { unsigned char nonceodd[TPM_NONCE_SIZE]; unsigned char enonce1[TPM_NONCE_SIZE]; @@ -611,14 +659,14 @@ int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, ret = TSS_authhmac(authdata1, keyauth, TPM_NONCE_SIZE, enonce1, nonceodd, cont, sizeof(uint32_t), &ordinal, - bloblen, blob, + enclen, encdata, 0, 0); if (ret < 0) return ret; - ret = TSS_authhmac(authdata2, blobauth, TPM_NONCE_SIZE, + ret = TSS_authhmac(authdata2, decauth, TPM_NONCE_SIZE, enonce2, nonceodd, cont, sizeof(uint32_t), &ordinal, - bloblen, blob, + enclen, encdata, 0, 0); if (ret < 0) return ret; @@ -626,10 +674,10 @@ int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, /* build and send TPM request packet */ INIT_BUF(tb); store16(tb, TPM_TAG_RQU_AUTH2_COMMAND); - store32(tb, TPM_UNSEAL_SIZE + bloblen); + store32(tb, TPM_UNSEAL_SIZE + enclen); store32(tb, TPM_ORD_UNSEAL); store32(tb, keyhandle); - storebytes(tb, blob, bloblen); + storebytes(tb, encdata, enclen); store32(tb, authhandle1); storebytes(tb, nonceodd, TPM_NONCE_SIZE); store8(tb, cont); @@ -646,18 +694,18 @@ int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, return ret; } - *datalen = LOAD32(tb->data, TPM_DATA_OFFSET); + *_rawlen = LOAD32(tb->data, TPM_DATA_OFFSET); ret = TSS_checkhmac2(tb->data, ordinal, nonceodd, keyauth, SHA1_DIGEST_SIZE, - blobauth, SHA1_DIGEST_SIZE, + decauth, SHA1_DIGEST_SIZE, sizeof(uint32_t), TPM_DATA_OFFSET, - *datalen, TPM_DATA_OFFSET + sizeof(uint32_t), + *_rawlen, TPM_DATA_OFFSET + sizeof(uint32_t), 0, 0); if (ret < 0) { pr_info("TSS_checkhmac2 failed (%d)\n", ret); return ret; } - memcpy(data, tb->data + TPM_DATA_OFFSET + sizeof(uint32_t), *datalen); + memcpy(rawbuffer, tb->data + TPM_DATA_OFFSET + sizeof(uint32_t), *_rawlen); return 0; } EXPORT_SYMBOL_GPL(tpm_unseal); diff --git a/include/linux/tpm.h b/include/linux/tpm.h index b08539920f76..cbd13e03a869 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -93,6 +93,22 @@ static inline int tpm_get_random(struct tpm_chip *chip, u8 *data, size_t max) { #define TPM_RETURN_OFFSET 6 #define TPM_DATA_OFFSET 10 +enum tpm_entity_type { + TPM_ET_KEYHANDLE = 0x01, + TPM_ET_OWNER = 0x02, + TPM_ET_DATA = 0x03, + TPM_ET_SRK = 0x04, + TPM_ET_KEY = 0x05, + TPM_ET_REVOKE = 0x06, + TPM_ET_DEL_OWNER_BLOB = 0x07, + TPM_ET_DEL_ROW = 0x08, + TPM_ET_DEL_KEY_BLOB = 0x09, + TPM_ET_COUNTER = 0x0a, + TPM_ET_NV = 0x0b, + TPM_ET_OPERATOR = 0x0c, + TPM_ET_RESERVED_HANDLE = 0x40, +}; + struct tpm_buf { int len; unsigned char data[MAX_BUF_SIZE]; @@ -103,7 +119,8 @@ struct tpm_buf { extern int tpm_library_use(void); extern void tpm_library_unuse(void); -extern int tpm_seal(struct tpm_chip *chip, struct tpm_buf *tb, uint16_t keytype, +extern int tpm_seal(struct tpm_chip *chip, + struct tpm_buf *tb, enum tpm_entity_type keytype, uint32_t keyhandle, const unsigned char *keyauth, const unsigned char *data, uint32_t datalen, unsigned char *blob, uint32_t *bloblen, From patchwork Tue Aug 21 15:58:10 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 10571961 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 43919921 for ; Tue, 21 Aug 2018 15:58:21 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8B2EE2A521 for ; Tue, 21 Aug 2018 15:58:16 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 7EF932A525; Tue, 21 Aug 2018 15:58:16 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A797C2A521 for ; Tue, 21 Aug 2018 15:58:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728139AbeHUTS4 (ORCPT ); Tue, 21 Aug 2018 15:18:56 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:53910 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726967AbeHUTS4 (ORCPT ); Tue, 21 Aug 2018 15:18:56 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 4287B804B9F2; Tue, 21 Aug 2018 15:58:12 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-123-147.rdu2.redhat.com [10.10.123.147]) by smtp.corp.redhat.com (Postfix) with ESMTP id C901D2026D64; Tue, 21 Aug 2018 15:58:10 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 12/23] TPMLIB: Create tpm_{even, odd}_nonce structs to represent nonces From: David Howells To: denkenz@gmail.com, jarkko.sakkinen@linux.intel.com, jejb@linux.vnet.ibm.com Cc: keyrings@vger.kernel.org, linux-integrity@vger.kernel.org, tpmdd-devel@lists.sourceforge.net, linux-security-module@vger.kernel.org Date: Tue, 21 Aug 2018 16:58:10 +0100 Message-ID: <153486709034.13066.6676055815830934254.stgit@warthog.procyon.org.uk> In-Reply-To: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> References: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Tue, 21 Aug 2018 15:58:12 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Tue, 21 Aug 2018 15:58:12 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'dhowells@redhat.com' RCPT:'' Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Create a tpm_even_nonce struct and a tpm_odd_nonce struct to represent nonces in internal routines rather than directly using char arrays. Having two separate structures helps keep track of which nonce is used where. Signed-off-by: David Howells --- drivers/char/tpm/tpm-library.c | 151 +++++++++++++++++++++------------------- drivers/char/tpm/tpm-library.h | 10 ++- 2 files changed, 90 insertions(+), 71 deletions(-) diff --git a/drivers/char/tpm/tpm-library.c b/drivers/char/tpm/tpm-library.c index 7d1f55413f02..1c64282d1d0d 100644 --- a/drivers/char/tpm/tpm-library.c +++ b/drivers/char/tpm/tpm-library.c @@ -35,6 +35,19 @@ static atomic_t tpm_library_usage; static struct crypto_shash *tpm_hashalg; static struct crypto_shash *tpm_hmacalg; +static int tpm_gen_odd_nonce(struct tpm_chip *chip, + struct tpm_odd_nonce *ononce) +{ + int ret; + + ret = tpm_get_random(chip, ononce->data, TPM_NONCE_SIZE); + if (ret == TPM_NONCE_SIZE) + ret = 0; + else + pr_info("tpm_get_random failed (%d)\n", ret); + return ret; +} + static struct tpm_sdesc *tpm_init_sdesc(struct crypto_shash *alg) { struct tpm_sdesc *sdesc; @@ -124,23 +137,25 @@ out: * @digest: Result buffer - must be SHA1_DIGEST_SIZE in size * @key: The key to use in the HMAC generation * @keylen: The size of @key - * @h1: Even nonce - * @h2: Odd nonce - * @h3: Continuation flag + * @enonce: Even nonce + * @ononce: Odd nonce + * @cont: Continuation flag * @...: Pairs of size and pointer of data elements to load into hash * @0,0: Terminator * * calculate authorization info fields to send to TPM */ -static int TSS_authhmac(unsigned char *digest, const unsigned char *key, - unsigned int keylen, unsigned char *h1, - unsigned char *h2, unsigned char h3, ...) +static int TSS_authhmac(unsigned char *digest, + const unsigned char *key, unsigned keylen, + const struct tpm_even_nonce *enonce, + const struct tpm_odd_nonce *ononce, + unsigned char cont, + ...) { unsigned char paramdigest[SHA1_DIGEST_SIZE]; struct tpm_sdesc *sdesc; unsigned int dlen; unsigned char *data; - unsigned char c; int ret; va_list argp; @@ -150,11 +165,10 @@ static int TSS_authhmac(unsigned char *digest, const unsigned char *key, return PTR_ERR(sdesc); } - c = h3; ret = crypto_shash_init(&sdesc->shash); if (ret < 0) goto out; - va_start(argp, h3); + va_start(argp, cont); for (;;) { dlen = va_arg(argp, unsigned int); if (dlen == 0) @@ -174,9 +188,9 @@ static int TSS_authhmac(unsigned char *digest, const unsigned char *key, if (!ret) ret = TSS_rawhmac(digest, key, keylen, SHA1_DIGEST_SIZE, paramdigest, - TPM_NONCE_SIZE, h1, - TPM_NONCE_SIZE, h2, - 1, &c, + TPM_NONCE_SIZE, enonce->data, + TPM_NONCE_SIZE, ononce->data, + 1, &cont, 0, 0); out: kfree(sdesc); @@ -188,15 +202,15 @@ out: */ static int TSS_checkhmac1(unsigned char *buffer, const uint32_t command, - const unsigned char *ononce, - const unsigned char *key, - unsigned int keylen, ...) + const struct tpm_odd_nonce *ononce, + const unsigned char *key, unsigned keylen, + ...) { uint32_t bufsize; uint16_t tag; uint32_t ordinal; uint32_t result; - unsigned char *enonce; + struct tpm_even_nonce *enonce; unsigned char *continueflag; unsigned char *authdata; unsigned char testhmac[SHA1_DIGEST_SIZE]; @@ -217,7 +231,7 @@ static int TSS_checkhmac1(unsigned char *buffer, return -EINVAL; authdata = buffer + bufsize - SHA1_DIGEST_SIZE; continueflag = authdata - 1; - enonce = continueflag - TPM_NONCE_SIZE; + enonce = (void *)continueflag - TPM_NONCE_SIZE; sdesc = tpm_init_sdesc(tpm_hashalg); if (IS_ERR(sdesc)) { @@ -253,8 +267,8 @@ static int TSS_checkhmac1(unsigned char *buffer, ret = TSS_rawhmac(testhmac, key, keylen, SHA1_DIGEST_SIZE, paramdigest, - TPM_NONCE_SIZE, enonce, - TPM_NONCE_SIZE, ononce, + TPM_NONCE_SIZE, enonce->data, + TPM_NONCE_SIZE, ononce->data, 1, continueflag, 0, 0); if (ret < 0) @@ -270,24 +284,23 @@ out: /* * verify the AUTH2_COMMAND (unseal) result from TPM */ -static int TSS_checkhmac2(unsigned char *buffer, +static int TSS_checkhmac2(const unsigned char *buffer, const uint32_t command, - const unsigned char *ononce, - const unsigned char *key1, - unsigned int keylen1, - const unsigned char *key2, - unsigned int keylen2, ...) + const struct tpm_odd_nonce *ononce, + const unsigned char *key1, unsigned keylen1, + const unsigned char *key2, unsigned keylen2, + ...) { uint32_t bufsize; uint16_t tag; uint32_t ordinal; uint32_t result; - unsigned char *enonce1; - unsigned char *continueflag1; - unsigned char *authdata1; - unsigned char *enonce2; - unsigned char *continueflag2; - unsigned char *authdata2; + const struct tpm_even_nonce *enonce1; + const unsigned char *continueflag1; + const unsigned char *authdata1; + const struct tpm_even_nonce *enonce2; + const unsigned char *continueflag2; + const unsigned char *authdata2; unsigned char testhmac1[SHA1_DIGEST_SIZE]; unsigned char testhmac2[SHA1_DIGEST_SIZE]; unsigned char paramdigest[SHA1_DIGEST_SIZE]; @@ -311,8 +324,8 @@ static int TSS_checkhmac2(unsigned char *buffer, authdata2 = buffer + bufsize - (SHA1_DIGEST_SIZE); continueflag1 = authdata1 - 1; continueflag2 = authdata2 - 1; - enonce1 = continueflag1 - TPM_NONCE_SIZE; - enonce2 = continueflag2 - TPM_NONCE_SIZE; + enonce1 = (const void *)continueflag1 - TPM_NONCE_SIZE; + enonce2 = (const void *)continueflag2 - TPM_NONCE_SIZE; sdesc = tpm_init_sdesc(tpm_hashalg); if (IS_ERR(sdesc)) { @@ -349,8 +362,8 @@ static int TSS_checkhmac2(unsigned char *buffer, ret = TSS_rawhmac(testhmac1, key1, keylen1, SHA1_DIGEST_SIZE, paramdigest, - TPM_NONCE_SIZE, enonce1, - TPM_NONCE_SIZE, ononce, + TPM_NONCE_SIZE, enonce1->data, + TPM_NONCE_SIZE, ononce->data, 1, continueflag1, 0, 0); if (ret < 0) @@ -361,8 +374,8 @@ static int TSS_checkhmac2(unsigned char *buffer, } ret = TSS_rawhmac(testhmac2, key2, keylen2, SHA1_DIGEST_SIZE, paramdigest, - TPM_NONCE_SIZE, enonce2, - TPM_NONCE_SIZE, ononce, + TPM_NONCE_SIZE, enonce2->data, + TPM_NONCE_SIZE, ononce->data, 1, continueflag2, 0, 0); if (ret < 0) @@ -400,12 +413,12 @@ static int tpm_create_osap(struct tpm_chip *chip, const unsigned char *keyauth, enum tpm_entity_type keytype, uint32_t keyhandle) { - unsigned char enonce[TPM_NONCE_SIZE]; - unsigned char ononce[TPM_NONCE_SIZE]; + struct tpm_even_nonce enonce; + struct tpm_odd_nonce ononce; int ret; - ret = tpm_get_random(chip, ononce, TPM_NONCE_SIZE); - if (ret != TPM_NONCE_SIZE) + ret = tpm_gen_odd_nonce(chip, &ononce); + if (ret < 0) return ret; INIT_BUF(tb); @@ -414,7 +427,7 @@ static int tpm_create_osap(struct tpm_chip *chip, store32(tb, TPM_ORD_OSAP); store16(tb, keytype); store32(tb, keyhandle); - storebytes(tb, ononce, TPM_NONCE_SIZE); + storebytes(tb, ononce.data, TPM_NONCE_SIZE); ret = tpm_send_dump(chip, tb->data, MAX_BUF_SIZE, "creating OSAP session"); @@ -422,13 +435,13 @@ static int tpm_create_osap(struct tpm_chip *chip, return ret; s->handle = LOAD32(tb->data, TPM_DATA_OFFSET); - memcpy(s->enonce, &(tb->data[TPM_DATA_OFFSET + sizeof(uint32_t)]), + memcpy(s->enonce.data, &(tb->data[TPM_DATA_OFFSET + sizeof(uint32_t)]), TPM_NONCE_SIZE); - memcpy(enonce, &(tb->data[TPM_DATA_OFFSET + sizeof(uint32_t) + + memcpy(enonce.data, &(tb->data[TPM_DATA_OFFSET + sizeof(uint32_t) + TPM_NONCE_SIZE]), TPM_NONCE_SIZE); return TSS_rawhmac(s->secret, keyauth, SHA1_DIGEST_SIZE, - TPM_NONCE_SIZE, enonce, - TPM_NONCE_SIZE, ononce, + TPM_NONCE_SIZE, enonce.data, + TPM_NONCE_SIZE, ononce.data, 0, 0); } @@ -436,7 +449,7 @@ static int tpm_create_osap(struct tpm_chip *chip, * Create an object independent authorisation protocol (oiap) session */ static int tpm_create_oiap(struct tpm_chip *chip, struct tpm_buf *tb, - uint32_t *handle, unsigned char *nonce) + uint32_t *handle, struct tpm_even_nonce *enonce) { int ret; @@ -450,7 +463,7 @@ static int tpm_create_oiap(struct tpm_chip *chip, struct tpm_buf *tb, return ret; *handle = LOAD32(tb->data, TPM_DATA_OFFSET); - memcpy(nonce, &tb->data[TPM_DATA_OFFSET + sizeof(uint32_t)], + memcpy(enonce->data, &tb->data[TPM_DATA_OFFSET + sizeof(uint32_t)], TPM_NONCE_SIZE); return 0; } @@ -460,7 +473,7 @@ struct tpm_digests { unsigned char pubauth[SHA1_DIGEST_SIZE]; unsigned char xorwork[SHA1_DIGEST_SIZE * 2]; unsigned char xorhash[SHA1_DIGEST_SIZE]; - unsigned char nonceodd[TPM_NONCE_SIZE]; + struct tpm_odd_nonce ononce; }; /** @@ -517,13 +530,13 @@ int tpm_seal(struct tpm_chip *chip, /* calculate encrypted authorization value */ memcpy(td->xorwork, sess.secret, SHA1_DIGEST_SIZE); - memcpy(td->xorwork + SHA1_DIGEST_SIZE, sess.enonce, SHA1_DIGEST_SIZE); + memcpy(td->xorwork + SHA1_DIGEST_SIZE, sess.enonce.data, SHA1_DIGEST_SIZE); ret = TSS_sha1(td->xorwork, SHA1_DIGEST_SIZE * 2, td->xorhash); if (ret < 0) goto out; - ret = tpm_get_random(chip, td->nonceodd, TPM_NONCE_SIZE); - if (ret != TPM_NONCE_SIZE) + ret = tpm_gen_odd_nonce(chip, &td->ononce); + if (ret < 0) goto out; ordinal = htonl(TPM_ORD_SEAL); datsize = htonl(rawlen); @@ -538,7 +551,7 @@ int tpm_seal(struct tpm_chip *chip, if (pcrinfosize == 0) { /* no pcr info specified */ ret = TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE, - sess.enonce, td->nonceodd, cont, + &sess.enonce, &td->ononce, cont, sizeof(uint32_t), &ordinal, SHA1_DIGEST_SIZE, td->encauth, sizeof(uint32_t), &pcrsize, @@ -548,7 +561,7 @@ int tpm_seal(struct tpm_chip *chip, } else { /* pcr info specified */ ret = TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE, - sess.enonce, td->nonceodd, cont, + &sess.enonce, &td->ononce, cont, sizeof(uint32_t), &ordinal, SHA1_DIGEST_SIZE, td->encauth, sizeof(uint32_t), &pcrsize, @@ -572,7 +585,7 @@ int tpm_seal(struct tpm_chip *chip, store32(tb, rawlen); storebytes(tb, rawdata, rawlen); store32(tb, sess.handle); - storebytes(tb, td->nonceodd, TPM_NONCE_SIZE); + storebytes(tb, td->ononce.data, TPM_NONCE_SIZE); store8(tb, cont); storebytes(tb, td->pubauth, SHA1_DIGEST_SIZE); @@ -589,7 +602,7 @@ int tpm_seal(struct tpm_chip *chip, sizeof(uint32_t) + encdatasize; /* check the HMAC in the response */ - ret = TSS_checkhmac1(tb->data, ordinal, td->nonceodd, + ret = TSS_checkhmac1(tb->data, ordinal, &td->ononce, sess.secret, SHA1_DIGEST_SIZE, storedsize, TPM_DATA_OFFSET, 0, 0); @@ -625,9 +638,9 @@ int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, const unsigned char *decauth, unsigned char *rawbuffer, unsigned int *_rawlen) { - unsigned char nonceodd[TPM_NONCE_SIZE]; - unsigned char enonce1[TPM_NONCE_SIZE]; - unsigned char enonce2[TPM_NONCE_SIZE]; + struct tpm_odd_nonce ononce; + struct tpm_even_nonce enonce1; + struct tpm_even_nonce enonce2; unsigned char authdata1[SHA1_DIGEST_SIZE]; unsigned char authdata2[SHA1_DIGEST_SIZE]; uint32_t authhandle1 = 0; @@ -638,12 +651,12 @@ int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, int ret; /* sessions for unsealing key and data */ - ret = tpm_create_oiap(chip, tb, &authhandle1, enonce1); + ret = tpm_create_oiap(chip, tb, &authhandle1, &enonce1); if (ret < 0) { pr_info("Failed to create OIAP 1 (%d)\n", ret); return ret; } - ret = tpm_create_oiap(chip, tb, &authhandle2, enonce2); + ret = tpm_create_oiap(chip, tb, &authhandle2, &enonce2); if (ret < 0) { pr_info("Failed to create OIAP 2 (%d)\n", ret); return ret; @@ -651,20 +664,18 @@ int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, ordinal = htonl(TPM_ORD_UNSEAL); keyhndl = htonl(SRKHANDLE); - ret = tpm_get_random(chip, nonceodd, TPM_NONCE_SIZE); - if (ret != TPM_NONCE_SIZE) { - pr_info("tpm_get_random failed (%d)\n", ret); + ret = tpm_gen_odd_nonce(chip, &ononce); + if (ret < 0) return ret; - } ret = TSS_authhmac(authdata1, keyauth, TPM_NONCE_SIZE, - enonce1, nonceodd, cont, + &enonce1, &ononce, cont, sizeof(uint32_t), &ordinal, enclen, encdata, 0, 0); if (ret < 0) return ret; ret = TSS_authhmac(authdata2, decauth, TPM_NONCE_SIZE, - enonce2, nonceodd, cont, + &enonce2, &ononce, cont, sizeof(uint32_t), &ordinal, enclen, encdata, 0, 0); @@ -679,11 +690,11 @@ int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, store32(tb, keyhandle); storebytes(tb, encdata, enclen); store32(tb, authhandle1); - storebytes(tb, nonceodd, TPM_NONCE_SIZE); + storebytes(tb, ononce.data, TPM_NONCE_SIZE); store8(tb, cont); storebytes(tb, authdata1, SHA1_DIGEST_SIZE); store32(tb, authhandle2); - storebytes(tb, nonceodd, TPM_NONCE_SIZE); + storebytes(tb, ononce.data, TPM_NONCE_SIZE); store8(tb, cont); storebytes(tb, authdata2, SHA1_DIGEST_SIZE); @@ -695,7 +706,7 @@ int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, } *_rawlen = LOAD32(tb->data, TPM_DATA_OFFSET); - ret = TSS_checkhmac2(tb->data, ordinal, nonceodd, + ret = TSS_checkhmac2(tb->data, ordinal, &ononce, keyauth, SHA1_DIGEST_SIZE, decauth, SHA1_DIGEST_SIZE, sizeof(uint32_t), TPM_DATA_OFFSET, diff --git a/drivers/char/tpm/tpm-library.h b/drivers/char/tpm/tpm-library.h index 6f7571cc6d6c..ceb0ea1cd2bb 100644 --- a/drivers/char/tpm/tpm-library.h +++ b/drivers/char/tpm/tpm-library.h @@ -15,10 +15,18 @@ #define LOAD32N(buffer, offset) (*(uint32_t *)&buffer[offset]) #define LOAD16(buffer, offset) (ntohs(*(uint16_t *)&buffer[offset])) +struct tpm_even_nonce { + unsigned char data[TPM_NONCE_SIZE]; +}; + +struct tpm_odd_nonce { + unsigned char data[TPM_NONCE_SIZE]; +}; + struct tpm_osapsess { uint32_t handle; unsigned char secret[SHA1_DIGEST_SIZE]; - unsigned char enonce[TPM_NONCE_SIZE]; + struct tpm_even_nonce enonce; }; static inline void store8(struct tpm_buf *buf, const unsigned char value) From patchwork Tue Aug 21 15:58:17 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 10571965 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id CF5C6921 for ; Tue, 21 Aug 2018 15:58:23 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BBFF02A521 for ; Tue, 21 Aug 2018 15:58:21 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B02032A529; Tue, 21 Aug 2018 15:58:21 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 58D352A521 for ; Tue, 21 Aug 2018 15:58:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728142AbeHUTTC (ORCPT ); Tue, 21 Aug 2018 15:19:02 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:43508 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726967AbeHUTTC (ORCPT ); Tue, 21 Aug 2018 15:19:02 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id E626D40216E8; Tue, 21 Aug 2018 15:58:18 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-123-147.rdu2.redhat.com [10.10.123.147]) by smtp.corp.redhat.com (Postfix) with ESMTP id DA7251010413; Tue, 21 Aug 2018 15:58:17 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 13/23] TPMLIB: Rename store8() and storebytes() From: David Howells To: denkenz@gmail.com, jarkko.sakkinen@linux.intel.com, jejb@linux.vnet.ibm.com Cc: keyrings@vger.kernel.org, linux-integrity@vger.kernel.org, tpmdd-devel@lists.sourceforge.net, linux-security-module@vger.kernel.org Date: Tue, 21 Aug 2018 16:58:17 +0100 Message-ID: <153486709741.13066.7109350297231028843.stgit@warthog.procyon.org.uk> In-Reply-To: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> References: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Tue, 21 Aug 2018 15:58:19 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Tue, 21 Aug 2018 15:58:19 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'dhowells@redhat.com' RCPT:'' Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Rename store8() and storebytes() so that the names are the same length as for store16() and store32() and their parameters line up, making blocks of them easier to read. Signed-off-by: David Howells --- drivers/char/tpm/tpm-library.c | 28 ++++++++++++++-------------- drivers/char/tpm/tpm-library.h | 14 +++++++------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/drivers/char/tpm/tpm-library.c b/drivers/char/tpm/tpm-library.c index 1c64282d1d0d..1eea483cf36b 100644 --- a/drivers/char/tpm/tpm-library.c +++ b/drivers/char/tpm/tpm-library.c @@ -427,7 +427,7 @@ static int tpm_create_osap(struct tpm_chip *chip, store32(tb, TPM_ORD_OSAP); store16(tb, keytype); store32(tb, keyhandle); - storebytes(tb, ononce.data, TPM_NONCE_SIZE); + store_s(tb, ononce.data, TPM_NONCE_SIZE); ret = tpm_send_dump(chip, tb->data, MAX_BUF_SIZE, "creating OSAP session"); @@ -579,15 +579,15 @@ int tpm_seal(struct tpm_chip *chip, store32(tb, TPM_SEAL_SIZE + pcrinfosize + rawlen); store32(tb, TPM_ORD_SEAL); store32(tb, keyhandle); - storebytes(tb, td->encauth, SHA1_DIGEST_SIZE); + store_s(tb, td->encauth, SHA1_DIGEST_SIZE); store32(tb, pcrinfosize); - storebytes(tb, pcrinfo, pcrinfosize); + store_s(tb, pcrinfo, pcrinfosize); store32(tb, rawlen); - storebytes(tb, rawdata, rawlen); + store_s(tb, rawdata, rawlen); store32(tb, sess.handle); - storebytes(tb, td->ononce.data, TPM_NONCE_SIZE); - store8(tb, cont); - storebytes(tb, td->pubauth, SHA1_DIGEST_SIZE); + store_s(tb, td->ononce.data, TPM_NONCE_SIZE); + store_8(tb, cont); + store_s(tb, td->pubauth, SHA1_DIGEST_SIZE); ret = tpm_send_dump(chip, tb->data, MAX_BUF_SIZE, "sealing data"); @@ -688,15 +688,15 @@ int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, store32(tb, TPM_UNSEAL_SIZE + enclen); store32(tb, TPM_ORD_UNSEAL); store32(tb, keyhandle); - storebytes(tb, encdata, enclen); + store_s(tb, encdata, enclen); store32(tb, authhandle1); - storebytes(tb, ononce.data, TPM_NONCE_SIZE); - store8(tb, cont); - storebytes(tb, authdata1, SHA1_DIGEST_SIZE); + store_s(tb, ononce.data, TPM_NONCE_SIZE); + store_8(tb, cont); + store_s(tb, authdata1, SHA1_DIGEST_SIZE); store32(tb, authhandle2); - storebytes(tb, ononce.data, TPM_NONCE_SIZE); - store8(tb, cont); - storebytes(tb, authdata2, SHA1_DIGEST_SIZE); + store_s(tb, ononce.data, TPM_NONCE_SIZE); + store_8(tb, cont); + store_s(tb, authdata2, SHA1_DIGEST_SIZE); ret = tpm_send_dump(chip, tb->data, MAX_BUF_SIZE, "unsealing data"); diff --git a/drivers/char/tpm/tpm-library.h b/drivers/char/tpm/tpm-library.h index ceb0ea1cd2bb..c1af99dba08d 100644 --- a/drivers/char/tpm/tpm-library.h +++ b/drivers/char/tpm/tpm-library.h @@ -29,25 +29,25 @@ struct tpm_osapsess { struct tpm_even_nonce enonce; }; -static inline void store8(struct tpm_buf *buf, const unsigned char value) +static inline void store_8(struct tpm_buf *buf, unsigned char value) { buf->data[buf->len++] = value; } -static inline void store16(struct tpm_buf *buf, const uint16_t value) +static inline void store16(struct tpm_buf *buf, uint16_t value) { - *(uint16_t *) & buf->data[buf->len] = htons(value); + *(uint16_t *)&buf->data[buf->len] = htons(value); buf->len += sizeof value; } -static inline void store32(struct tpm_buf *buf, const uint32_t value) +static inline void store32(struct tpm_buf *buf, uint32_t value) { - *(uint32_t *) & buf->data[buf->len] = htonl(value); + *(uint32_t *)&buf->data[buf->len] = htonl(value); buf->len += sizeof value; } -static inline void storebytes(struct tpm_buf *buf, const unsigned char *in, - const int len) +static inline void store_s(struct tpm_buf *buf, const unsigned char *in, + int len) { memcpy(buf->data + buf->len, in, len); buf->len += len; From patchwork Tue Aug 21 15:58:24 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 10571969 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 9102C17E0 for ; Tue, 21 Aug 2018 15:58:27 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7CC7D2A9AE for ; Tue, 21 Aug 2018 15:58:27 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 701B02A9B9; Tue, 21 Aug 2018 15:58:27 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3230A2A9B1 for ; Tue, 21 Aug 2018 15:58:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728146AbeHUTTI (ORCPT ); Tue, 21 Aug 2018 15:19:08 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:53922 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1728145AbeHUTTI (ORCPT ); Tue, 21 Aug 2018 15:19:08 -0400 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 83481804B9F2; Tue, 21 Aug 2018 15:58:25 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-123-147.rdu2.redhat.com [10.10.123.147]) by smtp.corp.redhat.com (Postfix) with ESMTP id 927F4A9A06; Tue, 21 Aug 2018 15:58:24 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 14/23] TPMLIB: Make store_s() take a void* data argument, not unsigned char* From: David Howells To: denkenz@gmail.com, jarkko.sakkinen@linux.intel.com, jejb@linux.vnet.ibm.com Cc: keyrings@vger.kernel.org, linux-integrity@vger.kernel.org, tpmdd-devel@lists.sourceforge.net, linux-security-module@vger.kernel.org Date: Tue, 21 Aug 2018 16:58:24 +0100 Message-ID: <153486710407.13066.16921127654210787068.stgit@warthog.procyon.org.uk> In-Reply-To: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> References: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Tue, 21 Aug 2018 15:58:25 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Tue, 21 Aug 2018 15:58:25 +0000 (UTC) for IP:'10.11.54.5' DOMAIN:'int-mx05.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'dhowells@redhat.com' RCPT:'' Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Make store_s() (store arbitrarily-sized data) take a void* data argument, not unsigned char* so that it can be given a pointer to a structure to be included without the need to cast. Signed-off-by: David Howells --- drivers/char/tpm/tpm-library.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/char/tpm/tpm-library.h b/drivers/char/tpm/tpm-library.h index c1af99dba08d..861e67df27fc 100644 --- a/drivers/char/tpm/tpm-library.h +++ b/drivers/char/tpm/tpm-library.h @@ -46,8 +46,7 @@ static inline void store32(struct tpm_buf *buf, uint32_t value) buf->len += sizeof value; } -static inline void store_s(struct tpm_buf *buf, const unsigned char *in, - int len) +static inline void store_s(struct tpm_buf *buf, const void *in, int len) { memcpy(buf->data + buf->len, in, len); buf->len += len; From patchwork Tue Aug 21 15:58:30 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 10571973 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 738B617E0 for ; Tue, 21 Aug 2018 15:58:36 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 61AA72A9B1 for ; Tue, 21 Aug 2018 15:58:36 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 563102A9B9; Tue, 21 Aug 2018 15:58:36 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D0A692A9B1 for ; Tue, 21 Aug 2018 15:58:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728156AbeHUTTR (ORCPT ); Tue, 21 Aug 2018 15:19:17 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:44810 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1728145AbeHUTTQ (ORCPT ); Tue, 21 Aug 2018 15:19:16 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 4E32477741; Tue, 21 Aug 2018 15:58:33 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-123-147.rdu2.redhat.com [10.10.123.147]) by smtp.corp.redhat.com (Postfix) with ESMTP id 420062026D64; Tue, 21 Aug 2018 15:58:32 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 15/23] TPMLIB: Use __be32 rather than int32_t and use cpu_to_beX() and co. From: David Howells To: denkenz@gmail.com, jarkko.sakkinen@linux.intel.com, jejb@linux.vnet.ibm.com Cc: keyrings@vger.kernel.org, linux-integrity@vger.kernel.org, tpmdd-devel@lists.sourceforge.net, linux-security-module@vger.kernel.org Date: Tue, 21 Aug 2018 16:58:30 +0100 Message-ID: <153486711068.13066.16019818060381526218.stgit@warthog.procyon.org.uk> In-Reply-To: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> References: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 21 Aug 2018 15:58:33 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 21 Aug 2018 15:58:33 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'dhowells@redhat.com' RCPT:'' Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Use __be32 rather than int32_t and use cpu_to_beX() and co. rather than htonl() and co. Signed-off-by: David Howells --- drivers/char/tpm/tpm-library.c | 58 ++++++++++++++++++---------------------- drivers/char/tpm/tpm-library.h | 14 +++++----- 2 files changed, 33 insertions(+), 39 deletions(-) diff --git a/drivers/char/tpm/tpm-library.c b/drivers/char/tpm/tpm-library.c index 1eea483cf36b..f14980be5ebb 100644 --- a/drivers/char/tpm/tpm-library.c +++ b/drivers/char/tpm/tpm-library.c @@ -201,15 +201,14 @@ out: * verify the AUTH1_COMMAND (Seal) result from TPM */ static int TSS_checkhmac1(unsigned char *buffer, - const uint32_t command, + __be32 ordinal, const struct tpm_odd_nonce *ononce, const unsigned char *key, unsigned keylen, ...) { uint32_t bufsize; uint16_t tag; - uint32_t ordinal; - uint32_t result; + __be32 result; struct tpm_even_nonce *enonce; unsigned char *continueflag; unsigned char *authdata; @@ -223,8 +222,7 @@ static int TSS_checkhmac1(unsigned char *buffer, bufsize = LOAD32(buffer, TPM_SIZE_OFFSET); tag = LOAD16(buffer, 0); - ordinal = command; - result = LOAD32N(buffer, TPM_RETURN_OFFSET); + result = LOAD32BE(buffer, TPM_RETURN_OFFSET); if (tag == TPM_TAG_RSP_COMMAND) return 0; if (tag != TPM_TAG_RSP_AUTH1_COMMAND) @@ -246,7 +244,7 @@ static int TSS_checkhmac1(unsigned char *buffer, if (ret < 0) goto out; ret = crypto_shash_update(&sdesc->shash, (const u8 *)&ordinal, - sizeof ordinal); + sizeof(ordinal)); if (ret < 0) goto out; va_start(argp, keylen); @@ -285,7 +283,7 @@ out: * verify the AUTH2_COMMAND (unseal) result from TPM */ static int TSS_checkhmac2(const unsigned char *buffer, - const uint32_t command, + __be32 ordinal, const struct tpm_odd_nonce *ononce, const unsigned char *key1, unsigned keylen1, const unsigned char *key2, unsigned keylen2, @@ -293,8 +291,7 @@ static int TSS_checkhmac2(const unsigned char *buffer, { uint32_t bufsize; uint16_t tag; - uint32_t ordinal; - uint32_t result; + __be32 result; const struct tpm_even_nonce *enonce1; const unsigned char *continueflag1; const unsigned char *authdata1; @@ -312,8 +309,7 @@ static int TSS_checkhmac2(const unsigned char *buffer, bufsize = LOAD32(buffer, TPM_SIZE_OFFSET); tag = LOAD16(buffer, 0); - ordinal = command; - result = LOAD32N(buffer, TPM_RETURN_OFFSET); + result = LOAD32BE(buffer, TPM_RETURN_OFFSET); if (tag == TPM_TAG_RSP_COMMAND) return 0; @@ -336,11 +332,11 @@ static int TSS_checkhmac2(const unsigned char *buffer, if (ret < 0) goto out; ret = crypto_shash_update(&sdesc->shash, (const u8 *)&result, - sizeof result); + sizeof(result)); if (ret < 0) goto out; ret = crypto_shash_update(&sdesc->shash, (const u8 *)&ordinal, - sizeof ordinal); + sizeof(ordinal)); if (ret < 0) goto out; @@ -508,9 +504,9 @@ int tpm_seal(struct tpm_chip *chip, struct tpm_osapsess sess; struct tpm_digests *td; unsigned char cont; - uint32_t ordinal; - uint32_t pcrsize; - uint32_t datsize; + __be32 ordinal_be; + __be32 rawlen_be; + __be32 pcrinfosize_be; int sealinfosize; int encdatasize; int storedsize; @@ -538,9 +534,9 @@ int tpm_seal(struct tpm_chip *chip, ret = tpm_gen_odd_nonce(chip, &td->ononce); if (ret < 0) goto out; - ordinal = htonl(TPM_ORD_SEAL); - datsize = htonl(rawlen); - pcrsize = htonl(pcrinfosize); + ordinal_be = cpu_to_be32(TPM_ORD_SEAL); + rawlen_be = cpu_to_be32(rawlen); + pcrinfosize_be = cpu_to_be32(pcrinfosize); cont = 0; /* encrypt data authorization key */ @@ -552,21 +548,21 @@ int tpm_seal(struct tpm_chip *chip, /* no pcr info specified */ ret = TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE, &sess.enonce, &td->ononce, cont, - sizeof(uint32_t), &ordinal, + sizeof(__be32), &ordinal_be, SHA1_DIGEST_SIZE, td->encauth, - sizeof(uint32_t), &pcrsize, - sizeof(uint32_t), &datsize, + sizeof(__be32), &pcrinfosize_be, + sizeof(__be32), &rawlen_be, rawlen, rawdata, 0, 0); } else { /* pcr info specified */ ret = TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE, &sess.enonce, &td->ononce, cont, - sizeof(uint32_t), &ordinal, + sizeof(__be32), &ordinal_be, SHA1_DIGEST_SIZE, td->encauth, - sizeof(uint32_t), &pcrsize, + sizeof(__be32), &pcrinfosize_be, pcrinfosize, pcrinfo, - sizeof(uint32_t), &datsize, + sizeof(__be32), &rawlen_be, rawlen, rawdata, 0, 0); } @@ -602,7 +598,7 @@ int tpm_seal(struct tpm_chip *chip, sizeof(uint32_t) + encdatasize; /* check the HMAC in the response */ - ret = TSS_checkhmac1(tb->data, ordinal, &td->ononce, + ret = TSS_checkhmac1(tb->data, ordinal_be, &td->ononce, sess.secret, SHA1_DIGEST_SIZE, storedsize, TPM_DATA_OFFSET, 0, 0); @@ -646,8 +642,7 @@ int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, uint32_t authhandle1 = 0; uint32_t authhandle2 = 0; unsigned char cont = 0; - uint32_t ordinal; - uint32_t keyhndl; + __be32 ordinal; int ret; /* sessions for unsealing key and data */ @@ -662,21 +657,20 @@ int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, return ret; } - ordinal = htonl(TPM_ORD_UNSEAL); - keyhndl = htonl(SRKHANDLE); + ordinal = cpu_to_be32(TPM_ORD_UNSEAL); ret = tpm_gen_odd_nonce(chip, &ononce); if (ret < 0) return ret; ret = TSS_authhmac(authdata1, keyauth, TPM_NONCE_SIZE, &enonce1, &ononce, cont, - sizeof(uint32_t), &ordinal, + sizeof(__be32), &ordinal, enclen, encdata, 0, 0); if (ret < 0) return ret; ret = TSS_authhmac(authdata2, decauth, TPM_NONCE_SIZE, &enonce2, &ononce, cont, - sizeof(uint32_t), &ordinal, + sizeof(__be32), &ordinal, enclen, encdata, 0, 0); if (ret < 0) diff --git a/drivers/char/tpm/tpm-library.h b/drivers/char/tpm/tpm-library.h index 861e67df27fc..c12d451704a2 100644 --- a/drivers/char/tpm/tpm-library.h +++ b/drivers/char/tpm/tpm-library.h @@ -11,9 +11,9 @@ */ -#define LOAD32(buffer, offset) (ntohl(*(uint32_t *)&buffer[offset])) -#define LOAD32N(buffer, offset) (*(uint32_t *)&buffer[offset]) -#define LOAD16(buffer, offset) (ntohs(*(uint16_t *)&buffer[offset])) +#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]; @@ -36,14 +36,14 @@ static inline void store_8(struct tpm_buf *buf, unsigned char value) static inline void store16(struct tpm_buf *buf, uint16_t value) { - *(uint16_t *)&buf->data[buf->len] = htons(value); - buf->len += sizeof value; + *(__be16 *)&buf->data[buf->len] = cpu_to_be16(value); + buf->len += sizeof(value); } static inline void store32(struct tpm_buf *buf, uint32_t value) { - *(uint32_t *)&buf->data[buf->len] = htonl(value); - buf->len += sizeof value; + *(__be32 *)&buf->data[buf->len] = cpu_to_be32(value); + buf->len += sizeof(value); } static inline void store_s(struct tpm_buf *buf, const void *in, int len) From patchwork Tue Aug 21 15:58:38 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 10571977 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C4D1317E0 for ; Tue, 21 Aug 2018 15:58:44 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B43182A9AE for ; Tue, 21 Aug 2018 15:58:44 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A86422A9B3; Tue, 21 Aug 2018 15:58:44 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E7CFF2A9B1 for ; Tue, 21 Aug 2018 15:58:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728161AbeHUTTZ (ORCPT ); Tue, 21 Aug 2018 15:19:25 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:44824 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1728145AbeHUTTY (ORCPT ); Tue, 21 Aug 2018 15:19:24 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 1409A7721C; Tue, 21 Aug 2018 15:58:40 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-123-147.rdu2.redhat.com [10.10.123.147]) by smtp.corp.redhat.com (Postfix) with ESMTP id E1E7D1010413; Tue, 21 Aug 2018 15:58:38 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 16/23] TPMLIB: Put more comments into the HMAC generation functions From: David Howells To: denkenz@gmail.com, jarkko.sakkinen@linux.intel.com, jejb@linux.vnet.ibm.com Cc: keyrings@vger.kernel.org, linux-integrity@vger.kernel.org, tpmdd-devel@lists.sourceforge.net, linux-security-module@vger.kernel.org Date: Tue, 21 Aug 2018 16:58:38 +0100 Message-ID: <153486711844.13066.4588463993575735370.stgit@warthog.procyon.org.uk> In-Reply-To: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> References: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 21 Aug 2018 15:58:40 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 21 Aug 2018 15:58:40 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'dhowells@redhat.com' RCPT:'' Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Put more comments into the HMAC generation functions in the TPM call library so that it's easier to see how it relates to the request and response tables in the documents. Signed-off-by: David Howells --- drivers/char/tpm/tpm-library.c | 161 +++++++++++++++++++++------------------- 1 file changed, 83 insertions(+), 78 deletions(-) diff --git a/drivers/char/tpm/tpm-library.c b/drivers/char/tpm/tpm-library.c index f14980be5ebb..46cd12d30ec6 100644 --- a/drivers/char/tpm/tpm-library.c +++ b/drivers/char/tpm/tpm-library.c @@ -85,7 +85,7 @@ static int TSS_sha1(const unsigned char *data, unsigned int datalen, * @key: The key to use in the HMAC generation * @keylen: The size of @key * @...: Pairs of size and pointer of data elements to load into hmac - * @0,0: Terminator + * @0,NULL: Terminator */ static int TSS_rawhmac(unsigned char *digest, const unsigned char *key, unsigned keylen, @@ -113,13 +113,9 @@ static int TSS_rawhmac(unsigned char *digest, va_start(argp, keylen); for (;;) { dlen = va_arg(argp, unsigned int); - if (dlen == 0) - break; data = va_arg(argp, unsigned char *); - if (data == NULL) { - ret = -EINVAL; + if (!data) break; - } ret = crypto_shash_update(&sdesc->shash, data, dlen); if (ret < 0) break; @@ -141,9 +137,9 @@ out: * @ononce: Odd nonce * @cont: Continuation flag * @...: Pairs of size and pointer of data elements to load into hash - * @0,0: Terminator + * @0,NULL: Terminator * - * calculate authorization info fields to send to TPM + * Calculate authorization info fields to send to TPM */ static int TSS_authhmac(unsigned char *digest, const unsigned char *key, unsigned keylen, @@ -171,13 +167,9 @@ static int TSS_authhmac(unsigned char *digest, va_start(argp, cont); for (;;) { dlen = va_arg(argp, unsigned int); - if (dlen == 0) - break; data = va_arg(argp, unsigned char *); - if (!data) { - ret = -EINVAL; + if (!data) break; - } ret = crypto_shash_update(&sdesc->shash, data, dlen); if (ret < 0) break; @@ -187,18 +179,25 @@ static int TSS_authhmac(unsigned char *digest, ret = crypto_shash_final(&sdesc->shash, paramdigest); if (!ret) ret = TSS_rawhmac(digest, key, keylen, - SHA1_DIGEST_SIZE, paramdigest, - TPM_NONCE_SIZE, enonce->data, - TPM_NONCE_SIZE, ononce->data, - 1, &cont, - 0, 0); + /* 1H1 */ SHA1_DIGEST_SIZE, paramdigest, + /* 2H1 */ TPM_NONCE_SIZE, enonce->data, + /* 3H1 */ TPM_NONCE_SIZE, ononce->data, + /* 4H1 */ 1, &cont, + 0, NULL); out: kfree(sdesc); return ret; } -/* - * verify the AUTH1_COMMAND (Seal) result from TPM +/** + * TSS_checkhmac1 - Verify the result of an AUTH1_COMMAND (eg. Seal) + * @digest: Reply buffer + * @ordinal: The command ID, BE form + * @ononce: Odd nonce + * @key: The key to use in the HMAC generation + * @keylen: The size of @key + * @...: Pairs of size and pointer of data elements to load into hash + * @0,NULL: Terminator */ static int TSS_checkhmac1(unsigned char *buffer, __be32 ordinal, @@ -231,6 +230,9 @@ static int TSS_checkhmac1(unsigned char *buffer, continueflag = authdata - 1; enonce = (void *)continueflag - TPM_NONCE_SIZE; + /* Load the 1S, 2S, 3S, ... marked fields into a hash. The digest + * value is then 1H1 loaded into the HMAC below. + */ sdesc = tpm_init_sdesc(tpm_hashalg); if (IS_ERR(sdesc)) { pr_info("Can't alloc %s\n", tpm_hash_alg); @@ -240,19 +242,19 @@ static int TSS_checkhmac1(unsigned char *buffer, if (ret < 0) goto out; ret = crypto_shash_update(&sdesc->shash, (const u8 *)&result, - sizeof result); + sizeof(result)); /* 1S */ if (ret < 0) goto out; ret = crypto_shash_update(&sdesc->shash, (const u8 *)&ordinal, - sizeof(ordinal)); + sizeof(ordinal)); /* 2S */ if (ret < 0) goto out; va_start(argp, keylen); for (;;) { dlen = va_arg(argp, unsigned int); - if (dlen == 0) - break; dpos = va_arg(argp, unsigned int); + if (!dlen && !dpos) + break; ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen); if (ret < 0) break; @@ -263,12 +265,13 @@ static int TSS_checkhmac1(unsigned char *buffer, if (ret < 0) goto out; + /* Generate the HMAC digest */ ret = TSS_rawhmac(testhmac, key, keylen, - SHA1_DIGEST_SIZE, paramdigest, - TPM_NONCE_SIZE, enonce->data, - TPM_NONCE_SIZE, ononce->data, - 1, continueflag, - 0, 0); + /* 1H1 */ SHA1_DIGEST_SIZE, paramdigest, + /* 2H1 */ TPM_NONCE_SIZE, enonce->data, + /* 3H1 */ TPM_NONCE_SIZE, ononce->data, + /* 4H1 */ 1, continueflag, + 0, NULL); if (ret < 0) goto out; @@ -279,7 +282,18 @@ out: return ret; } -/* +/** + * TSS_checkhmac2 - Verify the result of an AUTH2_COMMAND (eg. Unseal) + * @digest: Reply buffer + * @ordinal: The command ID, BE form + * @ononce: Odd nonce + * @key1: The key to use in the authorisation session HMAC generation (nH1) + * @keylen1: The size of @key1 + * @key2: The key to use in the data session HMAC generation (nH2) + * @keylen2: The size of @key2 + * @...: Pairs of size and pointer of data elements to load into hash + * @0,NULL: Terminator + * * verify the AUTH2_COMMAND (unseal) result from TPM */ static int TSS_checkhmac2(const unsigned char *buffer, @@ -323,6 +337,9 @@ static int TSS_checkhmac2(const unsigned char *buffer, enonce1 = (const void *)continueflag1 - TPM_NONCE_SIZE; enonce2 = (const void *)continueflag2 - TPM_NONCE_SIZE; + /* Load the 1S, 2S, 3S, ... marked fields into a hash. The digest + * value is then 1H1 loaded into the HMAC below. + */ sdesc = tpm_init_sdesc(tpm_hashalg); if (IS_ERR(sdesc)) { pr_info("Can't alloc %s\n", tpm_hash_alg); @@ -332,20 +349,20 @@ static int TSS_checkhmac2(const unsigned char *buffer, if (ret < 0) goto out; ret = crypto_shash_update(&sdesc->shash, (const u8 *)&result, - sizeof(result)); + sizeof(result)); /* 1S */ if (ret < 0) goto out; ret = crypto_shash_update(&sdesc->shash, (const u8 *)&ordinal, - sizeof(ordinal)); + sizeof(ordinal)); /* 2S */ if (ret < 0) goto out; va_start(argp, keylen2); for (;;) { dlen = va_arg(argp, unsigned int); - if (dlen == 0) - break; dpos = va_arg(argp, unsigned int); + if (!dlen && !dpos) + break; ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen); if (ret < 0) break; @@ -357,11 +374,11 @@ static int TSS_checkhmac2(const unsigned char *buffer, goto out; ret = TSS_rawhmac(testhmac1, key1, keylen1, - SHA1_DIGEST_SIZE, paramdigest, - TPM_NONCE_SIZE, enonce1->data, - TPM_NONCE_SIZE, ononce->data, - 1, continueflag1, - 0, 0); + /* 1H1 */ SHA1_DIGEST_SIZE, paramdigest, + /* 2H1 */ TPM_NONCE_SIZE, enonce1->data, + /* 3H1 */ TPM_NONCE_SIZE, ononce->data, + /* 4H1 */ 1, continueflag1, + 0, NULL); if (ret < 0) goto out; if (memcmp(testhmac1, authdata1, SHA1_DIGEST_SIZE)) { @@ -369,11 +386,11 @@ static int TSS_checkhmac2(const unsigned char *buffer, goto out; } ret = TSS_rawhmac(testhmac2, key2, keylen2, - SHA1_DIGEST_SIZE, paramdigest, - TPM_NONCE_SIZE, enonce2->data, - TPM_NONCE_SIZE, ononce->data, - 1, continueflag2, - 0, 0); + /* 1H2 */ SHA1_DIGEST_SIZE, paramdigest, + /* 2H2 */ TPM_NONCE_SIZE, enonce2->data, + /* 3H2 */ TPM_NONCE_SIZE, ononce->data, + /* 4H2 */ 1, continueflag2, + 0, NULL); if (ret < 0) goto out; if (memcmp(testhmac2, authdata2, SHA1_DIGEST_SIZE)) @@ -438,7 +455,7 @@ static int tpm_create_osap(struct tpm_chip *chip, return TSS_rawhmac(s->secret, keyauth, SHA1_DIGEST_SIZE, TPM_NONCE_SIZE, enonce.data, TPM_NONCE_SIZE, ononce.data, - 0, 0); + 0, NULL); } /* @@ -484,7 +501,7 @@ struct tpm_digests { * @encbuffer: Buffer to hold the encrypted data (max SHA1_DIGEST_SIZE) * @_enclen: Where to place the size of the encrypted data * @encauth: 'Password' to use to encrypt authorisation key - * @pcrinfo: Information on PCR register values to seal to + * @pcrinfo: Information on PCR register values to seal to (must not be NULL) * @pcrinfosize: size of @pcrinfo * * Have the TPM seal (encrypt) the data in the data buffer. The encryption is @@ -544,28 +561,16 @@ int tpm_seal(struct tpm_chip *chip, td->encauth[i] = td->xorhash[i] ^ encauth[i]; /* calculate authorization HMAC value */ - if (pcrinfosize == 0) { - /* no pcr info specified */ - ret = TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE, - &sess.enonce, &td->ononce, cont, - sizeof(__be32), &ordinal_be, - SHA1_DIGEST_SIZE, td->encauth, - sizeof(__be32), &pcrinfosize_be, - sizeof(__be32), &rawlen_be, - rawlen, rawdata, - 0, 0); - } else { - /* pcr info specified */ - ret = TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE, - &sess.enonce, &td->ononce, cont, - sizeof(__be32), &ordinal_be, - SHA1_DIGEST_SIZE, td->encauth, - sizeof(__be32), &pcrinfosize_be, - pcrinfosize, pcrinfo, - sizeof(__be32), &rawlen_be, - rawlen, rawdata, - 0, 0); - } + BUG_ON(!pcrinfo); + ret = TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE, + &sess.enonce, &td->ononce, cont, + /* 1S */ sizeof(__be32), &ordinal_be, + /* 2S */ SHA1_DIGEST_SIZE, td->encauth, + /* 3S */ sizeof(__be32), &pcrinfosize_be, + /* 4S */ pcrinfosize, pcrinfo, + /* 5S */ sizeof(__be32), &rawlen_be, + /* 6S */ rawlen, rawdata, + 0, NULL); if (ret < 0) goto out; @@ -600,8 +605,8 @@ int tpm_seal(struct tpm_chip *chip, /* check the HMAC in the response */ ret = TSS_checkhmac1(tb->data, ordinal_be, &td->ononce, sess.secret, SHA1_DIGEST_SIZE, - storedsize, TPM_DATA_OFFSET, - 0, 0); + /* 3S */ storedsize, TPM_DATA_OFFSET, + 0, NULL); /* copy the encrypted data to caller's buffer */ if (!ret) { @@ -663,16 +668,16 @@ int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, return ret; ret = TSS_authhmac(authdata1, keyauth, TPM_NONCE_SIZE, &enonce1, &ononce, cont, - sizeof(__be32), &ordinal, - enclen, encdata, - 0, 0); + /* 1S */ sizeof(__be32), &ordinal, + /* 2S */ enclen, encdata, + 0, NULL); if (ret < 0) return ret; ret = TSS_authhmac(authdata2, decauth, TPM_NONCE_SIZE, &enonce2, &ononce, cont, - sizeof(__be32), &ordinal, - enclen, encdata, - 0, 0); + /* 1S */ sizeof(__be32), &ordinal, + /* 2S */ enclen, encdata, + 0, NULL); if (ret < 0) return ret; @@ -703,8 +708,8 @@ int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, ret = TSS_checkhmac2(tb->data, ordinal, &ononce, keyauth, SHA1_DIGEST_SIZE, decauth, SHA1_DIGEST_SIZE, - sizeof(uint32_t), TPM_DATA_OFFSET, - *_rawlen, TPM_DATA_OFFSET + sizeof(uint32_t), + /* 3S */ sizeof(uint32_t), TPM_DATA_OFFSET, + /* 4S */ *_rawlen, TPM_DATA_OFFSET + sizeof(uint32_t), 0, 0); if (ret < 0) { pr_info("TSS_checkhmac2 failed (%d)\n", ret); From patchwork Tue Aug 21 15:58:45 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 10571981 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 586E817E0 for ; Tue, 21 Aug 2018 15:58:50 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4741F2A9B1 for ; Tue, 21 Aug 2018 15:58:50 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 3B3D82A9B4; Tue, 21 Aug 2018 15:58:50 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7921C2A9B1 for ; Tue, 21 Aug 2018 15:58:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728162AbeHUTTa (ORCPT ); Tue, 21 Aug 2018 15:19:30 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:59550 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1728145AbeHUTTa (ORCPT ); Tue, 21 Aug 2018 15:19:30 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id BA8CC40201CA; Tue, 21 Aug 2018 15:58:46 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-123-147.rdu2.redhat.com [10.10.123.147]) by smtp.corp.redhat.com (Postfix) with ESMTP id ABBC92166BA1; Tue, 21 Aug 2018 15:58:45 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 17/23] TPMLIB: Provide a wrapper to load bytes out of the reply From: David Howells To: denkenz@gmail.com, jarkko.sakkinen@linux.intel.com, jejb@linux.vnet.ibm.com Cc: keyrings@vger.kernel.org, linux-integrity@vger.kernel.org, tpmdd-devel@lists.sourceforge.net, linux-security-module@vger.kernel.org Date: Tue, 21 Aug 2018 16:58:45 +0100 Message-ID: <153486712522.13066.16199758850117818658.stgit@warthog.procyon.org.uk> In-Reply-To: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> References: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Tue, 21 Aug 2018 15:58:46 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Tue, 21 Aug 2018 15:58:46 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'dhowells@redhat.com' RCPT:'' Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Provide a wrapper for memcpy to load bytes out of the reply, similar to LOAD32() and friends. Signed-off-by: David Howells --- 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]; }; From patchwork Tue Aug 21 15:58:51 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 10571985 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2690C17E0 for ; Tue, 21 Aug 2018 15:58:56 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 15BB92A9AE for ; Tue, 21 Aug 2018 15:58:56 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 09F4F2A9B3; Tue, 21 Aug 2018 15:58:56 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A98A82A9B1 for ; Tue, 21 Aug 2018 15:58:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728166AbeHUTTh (ORCPT ); Tue, 21 Aug 2018 15:19:37 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:45178 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1727593AbeHUTTh (ORCPT ); Tue, 21 Aug 2018 15:19:37 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 58AB4402178A; Tue, 21 Aug 2018 15:58:53 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-123-147.rdu2.redhat.com [10.10.123.147]) by smtp.corp.redhat.com (Postfix) with ESMTP id 64FB91010413; Tue, 21 Aug 2018 15:58:52 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 18/23] TPMLIB: Encapsulate XOR-based encryption with authkey derivative From: David Howells To: denkenz@gmail.com, jarkko.sakkinen@linux.intel.com, jejb@linux.vnet.ibm.com Cc: keyrings@vger.kernel.org, linux-integrity@vger.kernel.org, tpmdd-devel@lists.sourceforge.net, linux-security-module@vger.kernel.org Date: Tue, 21 Aug 2018 16:58:51 +0100 Message-ID: <153486713189.13066.10919642243213217779.stgit@warthog.procyon.org.uk> In-Reply-To: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> References: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Tue, 21 Aug 2018 15:58:53 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Tue, 21 Aug 2018 15:58:53 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'dhowells@redhat.com' RCPT:'' Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Encapsulate XOR-based encryption with a symmetric key derived from the authkey so that it can be used in multiple functions. Signed-off-by: David Howells --- drivers/char/tpm/tpm-library.c | 42 +++++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/drivers/char/tpm/tpm-library.c b/drivers/char/tpm/tpm-library.c index 329b5c3f23a2..9234a2e7608f 100644 --- a/drivers/char/tpm/tpm-library.c +++ b/drivers/char/tpm/tpm-library.c @@ -489,6 +489,30 @@ struct tpm_digests { struct tpm_odd_nonce ononce; }; +/* + * Calculate an XOR-based symmetric key that can be used to encrypt protected + * data. The key is left in td->xorhash. + */ +static int tpm_calc_symmetric_authkey(struct tpm_digests *td, + const u8 *secret, + const struct tpm_even_nonce *enonce) +{ + memcpy(td->xorwork, secret, SHA1_DIGEST_SIZE); + memcpy(td->xorwork + SHA1_DIGEST_SIZE, enonce->data, SHA1_DIGEST_SIZE); + return TSS_sha1(td->xorwork, SHA1_DIGEST_SIZE * 2, td->xorhash); +} + +/* + * Encrypt/decrypt data with a previously calculated XOR-based symmetric key. + */ +static void tpm_crypt_with_authkey(const struct tpm_digests *td, + const u8 *data, u8 *buffer) +{ + int i; + for (i = 0; i < SHA1_DIGEST_SIZE; ++i) + buffer[i] = td->xorhash[i] ^ data[i]; +} + /** * tpm_seal - Encrypt one key according to another plus PCR state * @chip: The chip to use @@ -528,7 +552,6 @@ int tpm_seal(struct tpm_chip *chip, int encdatasize; int storedsize; int ret; - int i; /* alloc some work space for all the hashes */ td = kmalloc(sizeof *td, GFP_KERNEL); @@ -541,13 +564,18 @@ int tpm_seal(struct tpm_chip *chip, goto out; dump_sess(&sess); - /* calculate encrypted authorization value */ - memcpy(td->xorwork, sess.secret, SHA1_DIGEST_SIZE); - memcpy(td->xorwork + SHA1_DIGEST_SIZE, sess.enonce.data, SHA1_DIGEST_SIZE); - ret = TSS_sha1(td->xorwork, SHA1_DIGEST_SIZE * 2, td->xorhash); + /* We need to pass a 'password' to the TPM with which it will encrypt + * the sealed data before returning it. So that the password doesn't + * travel to the TPM in the clear, we generate a symmetric key from the + * negotiated and encrypted session data and encrypt the password with + * that. + */ + ret = tpm_calc_symmetric_authkey(td, sess.secret, &sess.enonce); if (ret < 0) goto out; + tpm_crypt_with_authkey(td, encauth, td->encauth); + /* Set up the parameters we will be sending */ ret = tpm_gen_odd_nonce(chip, &td->ononce); if (ret < 0) goto out; @@ -556,10 +584,6 @@ int tpm_seal(struct tpm_chip *chip, pcrinfosize_be = cpu_to_be32(pcrinfosize); cont = 0; - /* encrypt data authorization key */ - for (i = 0; i < SHA1_DIGEST_SIZE; ++i) - td->encauth[i] = td->xorhash[i] ^ encauth[i]; - /* calculate authorization HMAC value */ BUG_ON(!pcrinfo); ret = TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE, From patchwork Tue Aug 21 15:58:58 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 10571989 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D7DED17E0 for ; Tue, 21 Aug 2018 15:59:02 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C7B132A9B6 for ; Tue, 21 Aug 2018 15:59:02 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id BB6AF2A9B3; Tue, 21 Aug 2018 15:59:02 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4716A2A9B1 for ; Tue, 21 Aug 2018 15:59:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727593AbeHUTTn (ORCPT ); Tue, 21 Aug 2018 15:19:43 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:59566 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1727031AbeHUTTn (ORCPT ); Tue, 21 Aug 2018 15:19:43 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 0F303402315A; Tue, 21 Aug 2018 15:59:00 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-123-147.rdu2.redhat.com [10.10.123.147]) by smtp.corp.redhat.com (Postfix) with ESMTP id 03B131010413; Tue, 21 Aug 2018 15:58:58 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 19/23] TPMLIB: Add some debugging code From: David Howells To: denkenz@gmail.com, jarkko.sakkinen@linux.intel.com, jejb@linux.vnet.ibm.com Cc: keyrings@vger.kernel.org, linux-integrity@vger.kernel.org, tpmdd-devel@lists.sourceforge.net, linux-security-module@vger.kernel.org Date: Tue, 21 Aug 2018 16:58:58 +0100 Message-ID: <153486713849.13066.10617410138420494526.stgit@warthog.procyon.org.uk> In-Reply-To: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> References: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Tue, 21 Aug 2018 15:59:00 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Tue, 21 Aug 2018 15:59:00 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'dhowells@redhat.com' RCPT:'' Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Add some pr_devel() statements to make debugging easier. They only exist within the kernel if DEBUG is defined. Signed-off-by: David Howells --- drivers/char/tpm/tpm-library.c | 58 ++++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/drivers/char/tpm/tpm-library.c b/drivers/char/tpm/tpm-library.c index 9234a2e7608f..0676165322a3 100644 --- a/drivers/char/tpm/tpm-library.c +++ b/drivers/char/tpm/tpm-library.c @@ -21,6 +21,8 @@ #include #include "tpm-library.h" +#define kenter(fmt, ...) pr_devel("==>%s("fmt")\n", __func__, ## __VA_ARGS__) +#define kleave(fmt, ...) pr_devel("<==%s()"fmt"\n", __func__, ## __VA_ARGS__) static const char tpm_hmac_alg[] = "hmac(sha1)"; static const char tpm_hash_alg[] = "sha1"; @@ -95,7 +97,7 @@ static int TSS_rawhmac(unsigned char *digest, va_list argp; unsigned int dlen; unsigned char *data; - int ret; + int ret, s; sdesc = tpm_init_sdesc(tpm_hmacalg); if (IS_ERR(sdesc)) { @@ -111,11 +113,12 @@ static int TSS_rawhmac(unsigned char *digest, goto out; va_start(argp, keylen); - for (;;) { + for (s = 1;; s++) { dlen = va_arg(argp, unsigned int); data = va_arg(argp, unsigned char *); if (!data) break; + pr_devel("RAWHMAC %dH1: [%u] %*phN\n", s, dlen, dlen, data); ret = crypto_shash_update(&sdesc->shash, data, dlen); if (ret < 0) break; @@ -152,7 +155,7 @@ static int TSS_authhmac(unsigned char *digest, struct tpm_sdesc *sdesc; unsigned int dlen; unsigned char *data; - int ret; + int ret, s; va_list argp; sdesc = tpm_init_sdesc(tpm_hashalg); @@ -165,11 +168,12 @@ static int TSS_authhmac(unsigned char *digest, if (ret < 0) goto out; va_start(argp, cont); - for (;;) { + for (s = 1;; s++) { dlen = va_arg(argp, unsigned int); data = va_arg(argp, unsigned char *); if (!data) break; + pr_devel("AUTHHASH S%d: [%u] %*phN\n", s, dlen, dlen, data); ret = crypto_shash_update(&sdesc->shash, data, dlen); if (ret < 0) break; @@ -411,6 +415,9 @@ static int tpm_send_dump(struct tpm_chip *chip, struct tpm_buf *cmd, { int rc; + kenter(",{%u,%u},%s", + cmd->len, be32_to_cpu(*(__be32 *)(cmd->data + TPM_SIZE_OFFSET)), desc); + dump_tpm_buf(cmd); rc = tpm_send_command(chip, cmd->data, MAX_BUF_SIZE, desc); dump_tpm_buf(cmd); @@ -419,6 +426,7 @@ static int tpm_send_dump(struct tpm_chip *chip, struct tpm_buf *cmd, rc = -EPERM; else SET_BUF_OFFSET(cmd, TPM_DATA_OFFSET); + kleave(" = %d [%u]", rc, be32_to_cpu(*(__be32 *)(cmd->data + TPM_SIZE_OFFSET))); return rc; } @@ -434,6 +442,8 @@ static int tpm_create_osap(struct tpm_chip *chip, struct tpm_odd_nonce ononce; int ret; + kenter(""); + ret = tpm_gen_odd_nonce(chip, &ononce); if (ret < 0) return ret; @@ -448,16 +458,20 @@ static int tpm_create_osap(struct tpm_chip *chip, ret = tpm_send_dump(chip, tb, "creating OSAP session"); if (ret < 0) - return ret; + goto out; 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, - 0, NULL); + /* Calculate the encrypted shared secret */ + ret = TSS_rawhmac(s->secret, keyauth, SHA1_DIGEST_SIZE, + TPM_NONCE_SIZE, enonce.data, + TPM_NONCE_SIZE, ononce.data, + 0, NULL); +out: + kleave(" = %d [%08x]", ret, s->handle); + return ret; } /* @@ -468,6 +482,8 @@ static int tpm_create_oiap(struct tpm_chip *chip, struct tpm_buf *tb, { int ret; + kenter(""); + INIT_BUF(tb); store16(tb, TPM_TAG_RQU_COMMAND); store32(tb, TPM_OIAP_SIZE); @@ -478,6 +494,7 @@ static int tpm_create_oiap(struct tpm_chip *chip, struct tpm_buf *tb, *handle = LOAD32(tb); LOAD_S(tb, enonce->data, TPM_NONCE_SIZE); + kleave(" = 0 [%08x]", *handle); return 0; } @@ -553,6 +570,8 @@ int tpm_seal(struct tpm_chip *chip, int storedsize; int ret; + kenter(""); + /* alloc some work space for all the hashes */ td = kmalloc(sizeof *td, GFP_KERNEL); if (!td) @@ -641,6 +660,7 @@ int tpm_seal(struct tpm_chip *chip, } out: kfree(td); + kleave(" = %d", ret); return ret; } EXPORT_SYMBOL_GPL(tpm_seal); @@ -676,36 +696,38 @@ int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, __be32 ordinal; int ret; + kenter(""); + /* sessions for unsealing key and data */ ret = tpm_create_oiap(chip, tb, &authhandle1, &enonce1); if (ret < 0) { pr_info("Failed to create OIAP 1 (%d)\n", ret); - return ret; + goto out; } ret = tpm_create_oiap(chip, tb, &authhandle2, &enonce2); if (ret < 0) { pr_info("Failed to create OIAP 2 (%d)\n", ret); - return ret; + goto out; } ordinal = cpu_to_be32(TPM_ORD_UNSEAL); ret = tpm_gen_odd_nonce(chip, &ononce); if (ret < 0) - return ret; + goto out; ret = TSS_authhmac(authdata1, keyauth, TPM_NONCE_SIZE, &enonce1, &ononce, cont, /* 1S */ sizeof(__be32), &ordinal, /* 2S */ enclen, encdata, 0, NULL); if (ret < 0) - return ret; + goto out; ret = TSS_authhmac(authdata2, decauth, TPM_NONCE_SIZE, &enonce2, &ononce, cont, /* 1S */ sizeof(__be32), &ordinal, /* 2S */ enclen, encdata, 0, NULL); if (ret < 0) - return ret; + goto out; /* build and send TPM request packet */ INIT_BUF(tb); @@ -726,7 +748,7 @@ int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, ret = tpm_send_dump(chip, tb, "unsealing data"); if (ret < 0) { pr_info("authhmac failed (%d)\n", ret); - return ret; + goto out; } *_rawlen = LOAD32(tb); @@ -738,10 +760,12 @@ int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, 0, 0); if (ret < 0) { pr_info("TSS_checkhmac2 failed (%d)\n", ret); - return ret; + goto out; } LOAD_S(tb, rawbuffer, *_rawlen); - return 0; +out: + kleave(" = %d", ret); + return ret; } EXPORT_SYMBOL_GPL(tpm_unseal); From patchwork Tue Aug 21 15:59:05 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 10571993 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id CF5A01390 for ; Tue, 21 Aug 2018 15:59:09 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BF2FC2A9B1 for ; Tue, 21 Aug 2018 15:59:09 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B33372A9AE; Tue, 21 Aug 2018 15:59:09 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1861A2A9B1 for ; Tue, 21 Aug 2018 15:59:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727161AbeHUTTu (ORCPT ); Tue, 21 Aug 2018 15:19:50 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:53956 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1727031AbeHUTTu (ORCPT ); Tue, 21 Aug 2018 15:19:50 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id C068B8076825; Tue, 21 Aug 2018 15:59:06 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-123-147.rdu2.redhat.com [10.10.123.147]) by smtp.corp.redhat.com (Postfix) with ESMTP id B1F2A2166BA1; Tue, 21 Aug 2018 15:59:05 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 20/23] TPMLIB: Implement call to TPM_CreateWrapKey From: David Howells To: denkenz@gmail.com, jarkko.sakkinen@linux.intel.com, jejb@linux.vnet.ibm.com Cc: keyrings@vger.kernel.org, linux-integrity@vger.kernel.org, tpmdd-devel@lists.sourceforge.net, linux-security-module@vger.kernel.org Date: Tue, 21 Aug 2018 16:59:05 +0100 Message-ID: <153486714520.13066.16385120783665804621.stgit@warthog.procyon.org.uk> In-Reply-To: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> References: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Tue, 21 Aug 2018 15:59:06 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Tue, 21 Aug 2018 15:59:06 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'dhowells@redhat.com' RCPT:'' Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Implement a function to invoke TPM_CreateWrapKey. Signed-off-by: David Howells --- drivers/char/tpm/tpm-library.c | 248 ++++++++++++++++++++++++++++++++++++++++ include/linux/tpm.h | 16 ++- include/linux/tpm_command.h | 1 3 files changed, 264 insertions(+), 1 deletion(-) diff --git a/drivers/char/tpm/tpm-library.c b/drivers/char/tpm/tpm-library.c index 0676165322a3..3413abeb3635 100644 --- a/drivers/char/tpm/tpm-library.c +++ b/drivers/char/tpm/tpm-library.c @@ -500,6 +500,7 @@ static int tpm_create_oiap(struct tpm_chip *chip, struct tpm_buf *tb, struct tpm_digests { unsigned char encauth[SHA1_DIGEST_SIZE]; + unsigned char encauth2[SHA1_DIGEST_SIZE]; unsigned char pubauth[SHA1_DIGEST_SIZE]; unsigned char xorwork[SHA1_DIGEST_SIZE * 2]; unsigned char xorhash[SHA1_DIGEST_SIZE]; @@ -769,6 +770,253 @@ out: } EXPORT_SYMBOL_GPL(tpm_unseal); +enum tpm_key_usage { + TPM_KEY_SIGNING = 0x0010, + TPM_KEY_STORAGE = 0x0011, + TPM_KEY_IDENTITY = 0x0012, + TPM_KEY_AUTHCHANGE = 0x0013, + TPM_KEY_BIND = 0x0014, + TPM_KEY_LEGACY = 0x0015, + TPM_KEY_MIGRATE = 0x0016, +}; + +enum tpm_algorithm_id { + TPM_ALG_RSA = 0x00000001, + TPM_ALG_SHA = 0x00000004, + TPM_ALG_HMAC = 0x00000005, + TPM_ALG_AES128 = 0x00000006, + TPM_ALG_MGF1 = 0x00000007, + TPM_ALG_AES192 = 0x00000008, + TPM_ALG_AES256 = 0x00000009, + TPM_ALG_XOR = 0x0000000a, +}; + +enum tpm_enc_scheme { + TPM_ES_NONE = 0x0001, + TPM_ES_RSAESPKCSv15 = 0x0002, + TPM_ES_RSAESOAEP_SHA1_MGF1 = 0x0003, + TPM_ES_SYM_CTR = 0x0004, + TPM_ES_SYM_OFB = 0x0005, +}; + +enum tpm_sig_scheme { + TPM_SS_NONE = 0x0001, + TPM_SS_RSAESPKCSv15_SHA1 = 0x0002, + TPM_SS_RSAESPKCSv15_DER = 0x0003, + TPM_SS_RSAESPKCSv15_INFO = 0x0004, +}; + +enum tpm_auth_data_usage { + TPM_AUTH_NEVER = 0x00, + TPM_AUTH_ALWAYS = 0x01, + TPM_NO_READ_PUBKEY_AUTH = 0x03, +}; + +#define TPM_KEY_REDIRECTION 0x00000001 +#define TPM_KEY_MIGRATABLE 0x00000002 +#define TPM_KEY_ISVOLATILE 0x00000004 +#define TPM_KEY_PCRIGNOREDONREAD 0x00000008 +#define TPM_KEY_MIGRATEAUTHORITY 0x00000010 + +struct tpm_key { + struct tpm_struct_ver { + u8 major, minor, rev_major, rev_minor; + } ver; + __be16 key_usage; /* enum tpm_key_usage */ + __be32 key_flags; + u8 auth_data_usage; /* enum tpm_auth_data_usage */ + struct tpm_key_parms { + __be32 algorithm_id; /* enum tpm_algorithm_id */ + __be16 enc_scheme; /* enum tpm_enc_scheme */ + __be16 sig_scheme; /* enum tpm_sig_scheme */ + __be32 parm_size; + struct tpm_rsa_key_parms { + __be32 key_length; + __be32 num_primes; + __be32 exponent_size; + } __packed rsa; + } __packed parms; + __be32 pcr_info_size; + struct tpm_store_pubkey { + __be32 key_length; + u8 key_data[0]; + } __packed pub; + __be32 enc_data_size; + u8 enc_data[0]; +} __packed; + +/** + * tpm_create_wrap_key - Generate a new key and return it encrypted + * @chip: The chip to use + * @tb: Large scratch buffer for I/O + * @parent_type: Type of entity attached to @parent_handle + * @parent_handle: TPM-resident key used to encrypt + * @parent_auth: Parent authorisation HMAC key + * @usage_auth: Encrypted usage authdata for the key + * @migration_auth: Encrypted migration authdata for the key (or NULL) + * @_wrapped_key: Pointer to where to return the wrapped key (kmalloc'd) + * + * Have the TPM generate a new key and return it encrypted. The encryption is + * based on a key already resident in the TPM and may also include the state of + * one or more Platform Configuration Registers (PCRs). + * + * AUTH1 is used for sealing key. + */ +int tpm_create_wrap_key(struct tpm_chip *chip, + enum tpm_entity_type parent_type, + uint32_t parent_handle, + const unsigned char *parent_auth, + const unsigned char *usage_auth, + const unsigned char *migration_auth, + struct tpm_wrapped_key **_wrapped_key) +{ + struct tpm_wrapped_key *wrapped_key; + struct tpm_osapsess sess; + struct tpm_digests *td; + struct tpm_buf *tb; + struct tpm_key *result; + unsigned char cont; + __be32 ordinal_be; + int key_size; + int ret; + + struct tpm_key tpm_key = { + .ver = { 0x01, 0x01, 0x00, 0x00 }, + .key_usage = cpu_to_be16(TPM_KEY_SIGNING), + .key_flags = cpu_to_be32(0), + .auth_data_usage = TPM_AUTH_ALWAYS, + .parms.algorithm_id = cpu_to_be32(TPM_ALG_RSA), + .parms.enc_scheme = cpu_to_be16(TPM_ES_RSAESPKCSv15), + .parms.sig_scheme = cpu_to_be16(TPM_SS_RSAESPKCSv15_SHA1), + .parms.parm_size = cpu_to_be32(sizeof(struct tpm_rsa_key_parms)), + .parms.rsa.key_length = cpu_to_be32(2048), + .parms.rsa.num_primes = cpu_to_be32(2), + .parms.rsa.exponent_size = cpu_to_be32(0), + .pcr_info_size = cpu_to_be32(0), + .pub.key_length = cpu_to_be32(0), + .enc_data_size = cpu_to_be32(0), + }; + + kenter(""); + + if (migration_auth) + tpm_key.key_flags |= cpu_to_be32(TPM_KEY_MIGRATABLE); + + /* alloc some work space */ + tb = kmalloc(sizeof(*tb) + sizeof(*td), GFP_KERNEL); + if (!tb) + return -ENOMEM; + td = (void *)tb + sizeof(*tb); + + /* Get the encryption session */ + ret = tpm_create_osap(chip, tb, &sess, + parent_auth, parent_type, parent_handle); + if (ret < 0) + goto out; + dump_sess(&sess); + + /* We need to pass 'passwords' to the TPM with which it will encrypt + * the key before returning it. So that the passwords don't travel to + * the TPM in the clear, we generate a symmetric key from the + * negotiated and encrypted session data and encrypt the passwords with + * that. + */ + ret = tpm_calc_symmetric_authkey(td, sess.secret, &sess.enonce); + if (ret < 0) + goto out; + tpm_crypt_with_authkey(td, usage_auth, td->encauth); + if (migration_auth) + tpm_crypt_with_authkey(td, migration_auth, td->encauth2); + else + tpm_crypt_with_authkey(td, sess.enonce.data, td->encauth2); + + /* Set up the parameters we will be sending */ + ret = tpm_gen_odd_nonce(chip, &td->ononce); + if (ret < 0) + goto out; + + /* calculate authorization HMAC value */ + ordinal_be = cpu_to_be32(TPM_ORD_CREATEWRAPKEY); + cont = 0; + ret = TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE, + &sess.enonce, &td->ononce, cont, + /* 1S */ sizeof(__be32), &ordinal_be, + /* 2S */ SHA1_DIGEST_SIZE, td->encauth, + /* 3S */ SHA1_DIGEST_SIZE, td->encauth2, + /* 4S */ sizeof(tpm_key), &tpm_key, + 0, NULL); + if (ret < 0) + goto out; + + /* build and send the TPM request packet */ + INIT_BUF(tb); + store16(tb, TPM_TAG_RQU_AUTH1_COMMAND); + store32(tb, TPM_DATA_OFFSET + 44 + sizeof(tpm_key) + 45); + store32(tb, TPM_ORD_CREATEWRAPKEY); + store32(tb, parent_handle); + store_s(tb, td->encauth, SHA1_DIGEST_SIZE); + store_s(tb, td->encauth2, SHA1_DIGEST_SIZE); + store_s(tb, &tpm_key, sizeof(tpm_key)); + store32(tb, sess.handle); + store_s(tb, td->ononce.data, TPM_NONCE_SIZE); + store_8(tb, cont); + store_s(tb, td->pubauth, SHA1_DIGEST_SIZE); + + ret = tpm_send_dump(chip, tb, "creating key"); + if (ret < 0) + goto out; + + /* We need to work out how big the TPM_KEY or TPM_KEY12 struct we got + * back is. These structs have several variable-length fields inside + * to make parsing more difficult. However, they are only followed by + * fixed-length structs... + */ + SET_BUF_OFFSET(tb, TPM_SIZE_OFFSET); + key_size = LOAD32(tb); + key_size -= TPM_DATA_OFFSET; + key_size -= 2 * TPM_NONCE_SIZE + 1; + if (key_size < sizeof(tpm_key)) { + ret = -EBADMSG; + goto out; + } + + /* Check the HMAC in the response */ + ret = TSS_checkhmac1(tb, ordinal_be, &td->ononce, + sess.secret, SHA1_DIGEST_SIZE, + /* 3S */ key_size, TPM_DATA_OFFSET, + 0, NULL); + if (ret < 0) + goto out; + + /* Parse the key */ + result = (void *)tb->data + TPM_DATA_OFFSET; + ret = -EBADMSG; + if (key_size < sizeof(tpm_key) + be32_to_cpu(tpm_key.parms.rsa.key_length) / 8) + goto out; + if (memcmp(result, &tpm_key, offsetof(struct tpm_key, pub.key_length)) != 0) + goto out; + if (be32_to_cpu(result->pub.key_length) > + be32_to_cpu(tpm_key.parms.rsa.key_length) / 8) + goto out; + + ret = -ENOMEM; + wrapped_key = kmalloc(sizeof(struct tpm_wrapped_key) + key_size, GFP_KERNEL); + if (!wrapped_key) + goto out; + wrapped_key->data_len = key_size; + wrapped_key->pubkey_offset = offsetof(struct tpm_key, pub.key_data); + wrapped_key->pubkey_len = be32_to_cpu(result->pub.key_length); + memcpy(wrapped_key->data, result, key_size); + *_wrapped_key = wrapped_key; + ret = 0; + +out: + kfree(tb); + kleave(" = %d", ret); + return ret; +} +EXPORT_SYMBOL_GPL(tpm_create_wrap_key); + /** * tpm_library_use - Tell the TPM library we want to make use of it * diff --git a/include/linux/tpm.h b/include/linux/tpm.h index 398bfaef2325..0bc954ac8266 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -83,7 +83,7 @@ static inline int tpm_get_random(struct tpm_chip *chip, u8 *data, size_t max) { */ /* implementation specific TPM constants */ #define MAX_PCRINFO_SIZE 64 -#define MAX_BUF_SIZE 512 +#define MAX_BUF_SIZE (2048 - 4) #define TPM_GETRANDOM_SIZE 14 #define TPM_OSAP_SIZE 36 #define TPM_OIAP_SIZE 10 @@ -133,4 +133,18 @@ extern int tpm_unseal(struct tpm_chip *chip, struct tpm_buf *tb, const unsigned char *blobauth, unsigned char *data, unsigned int *datalen); +struct tpm_wrapped_key { + unsigned short data_len; + unsigned short pubkey_offset; + unsigned short pubkey_len; + u8 data[]; +}; + +extern int tpm_create_wrap_key(struct tpm_chip *chip, + enum tpm_entity_type parent_type, + uint32_t parent_handle, + const unsigned char *parent_auth, + const unsigned char *usage_auth, + const unsigned char *migration_auth, + struct tpm_wrapped_key **_wrapped_key); #endif diff --git a/include/linux/tpm_command.h b/include/linux/tpm_command.h index a3e0bb670e62..0417a3db7e8f 100644 --- a/include/linux/tpm_command.h +++ b/include/linux/tpm_command.h @@ -22,6 +22,7 @@ enum tpm_ordinal { TPM_ORD_PCR_READ = 21, TPM_ORD_SEAL = 23, TPM_ORD_UNSEAL = 24, + TPM_ORD_CREATEWRAPKEY = 31, TPM_ORD_GET_RANDOM = 70, TPM_ORD_CONTINUE_SELFTEST = 83, TPM_ORD_GET_CAP = 101, From patchwork Tue Aug 21 15:59:11 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 10571997 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 6A24817E0 for ; Tue, 21 Aug 2018 15:59:16 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 59D8B2A9AE for ; Tue, 21 Aug 2018 15:59:16 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 4E1552A9B3; Tue, 21 Aug 2018 15:59:16 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DEA7F2A9B1 for ; Tue, 21 Aug 2018 15:59:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728173AbeHUTT5 (ORCPT ); Tue, 21 Aug 2018 15:19:57 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:59578 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1727031AbeHUTT5 (ORCPT ); Tue, 21 Aug 2018 15:19:57 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 7A53840201D3; Tue, 21 Aug 2018 15:59:13 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-123-147.rdu2.redhat.com [10.10.123.147]) by smtp.corp.redhat.com (Postfix) with ESMTP id 6EEDB1010413; Tue, 21 Aug 2018 15:59:12 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 21/23] TPMLIB: Implement call to TPM_LoadKey2 From: David Howells To: denkenz@gmail.com, jarkko.sakkinen@linux.intel.com, jejb@linux.vnet.ibm.com Cc: keyrings@vger.kernel.org, linux-integrity@vger.kernel.org, tpmdd-devel@lists.sourceforge.net, linux-security-module@vger.kernel.org Date: Tue, 21 Aug 2018 16:59:11 +0100 Message-ID: <153486715192.13066.16960521772592007978.stgit@warthog.procyon.org.uk> In-Reply-To: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> References: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Tue, 21 Aug 2018 15:59:13 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Tue, 21 Aug 2018 15:59:13 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'dhowells@redhat.com' RCPT:'' Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Implement a function to invoke TPM_LoadKey2 Signed-off-by: David Howells --- drivers/char/tpm/tpm-library.c | 93 ++++++++++++++++++++++++++++++++++++++++ include/linux/tpm.h | 7 +++ include/linux/tpm_command.h | 1 3 files changed, 101 insertions(+) diff --git a/drivers/char/tpm/tpm-library.c b/drivers/char/tpm/tpm-library.c index 3413abeb3635..d279243ccc00 100644 --- a/drivers/char/tpm/tpm-library.c +++ b/drivers/char/tpm/tpm-library.c @@ -1017,6 +1017,99 @@ out: } EXPORT_SYMBOL_GPL(tpm_create_wrap_key); +/** + * tpm_load_key2 - Load a key and decrypt it + * @chip: The chip to use + * @tb: Large scratch buffer for I/O + * @parent_type: Type of entity attached to @parent_handle + * @parent_handle: TPM-resident key used to encrypt + * @parent_auth: Parent authorisation HMAC key + * @wrapped_key: The wrapped key + * @_key_handle: The TPM's handle on the key + * + * Have the TPM decrypt a key and load it into its memory. The TPM then + * returns a handle to the key that we can use in other operations. + * + * AUTH1 is used for sealing key. + */ +int tpm_load_key2(struct tpm_chip *chip, + enum tpm_entity_type parent_type, + uint32_t parent_handle, + const unsigned char *parent_auth, + const struct tpm_wrapped_key *wrapped_key, + uint32_t *_key_handle) +{ + struct tpm_osapsess sess; + struct tpm_digests *td; + struct tpm_buf *tb; + unsigned char cont; + __be32 ordinal_be; + int ret; + + kenter(""); + + /* alloc some work space */ + tb = kmalloc(sizeof(*tb) + sizeof(*td), GFP_KERNEL); + if (!tb) + return -ENOMEM; + td = (void *)tb + sizeof(*tb); + + /* Get the encryption session */ + ret = tpm_create_osap(chip, tb, &sess, + parent_auth, parent_type, parent_handle); + if (ret < 0) + goto out; + dump_sess(&sess); + + /* Set up the parameters we will be sending */ + ret = tpm_gen_odd_nonce(chip, &td->ononce); + if (ret < 0) + goto out; + + /* calculate authorization HMAC value */ + ordinal_be = cpu_to_be32(TPM_ORD_LOADKEY2); + cont = 0; + ret = TSS_authhmac(td->pubauth, sess.secret, SHA1_DIGEST_SIZE, + &sess.enonce, &td->ononce, cont, + /* 1S */ sizeof(__be32), &ordinal_be, + /* 2S */ wrapped_key->data_len, wrapped_key->data, + 0, NULL); + if (ret < 0) + goto out; + + /* build and send the TPM request packet */ + INIT_BUF(tb); + store16(tb, TPM_TAG_RQU_AUTH1_COMMAND); + store32(tb, TPM_DATA_OFFSET + 4 + wrapped_key->data_len + 45); + store32(tb, TPM_ORD_LOADKEY2); + store32(tb, parent_handle); + store_s(tb, wrapped_key->data, wrapped_key->data_len); + store32(tb, sess.handle); + store_s(tb, td->ononce.data, TPM_NONCE_SIZE); + store_8(tb, cont); + store_s(tb, td->pubauth, SHA1_DIGEST_SIZE); + + ret = tpm_send_dump(chip, tb, "loading key"); + if (ret < 0) + goto out; + + /* Check the HMAC in the response */ + ret = TSS_checkhmac1(tb, ordinal_be, &td->ononce, + sess.secret, SHA1_DIGEST_SIZE, + 0, NULL); + if (ret < 0) + goto out; + + *_key_handle = LOAD32(tb); + ret = 0; + +out: + kfree(tb); + kleave(" = %d [%08x]", ret, *_key_handle); + return ret; +} +EXPORT_SYMBOL_GPL(tpm_load_key2); + /** * tpm_library_use - Tell the TPM library we want to make use of it * diff --git a/include/linux/tpm.h b/include/linux/tpm.h index 0bc954ac8266..2be0decff93b 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -147,4 +147,11 @@ extern int tpm_create_wrap_key(struct tpm_chip *chip, const unsigned char *usage_auth, const unsigned char *migration_auth, struct tpm_wrapped_key **_wrapped_key); +extern int tpm_load_key2(struct tpm_chip *chip, + enum tpm_entity_type parent_type, + uint32_t parent_handle, + const unsigned char *parent_auth, + const struct tpm_wrapped_key *wrapped_key, + uint32_t *_key_handle); + #endif diff --git a/include/linux/tpm_command.h b/include/linux/tpm_command.h index 0417a3db7e8f..211d4ce75f67 100644 --- a/include/linux/tpm_command.h +++ b/include/linux/tpm_command.h @@ -23,6 +23,7 @@ enum tpm_ordinal { TPM_ORD_SEAL = 23, TPM_ORD_UNSEAL = 24, TPM_ORD_CREATEWRAPKEY = 31, + TPM_ORD_LOADKEY2 = 65, TPM_ORD_GET_RANDOM = 70, TPM_ORD_CONTINUE_SELFTEST = 83, TPM_ORD_GET_CAP = 101, From patchwork Tue Aug 21 15:59:18 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 10572001 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 62D6017E0 for ; Tue, 21 Aug 2018 15:59:22 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4D6942A9AE for ; Tue, 21 Aug 2018 15:59:22 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 41D5E2A9B3; Tue, 21 Aug 2018 15:59:22 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E73B32A9AE for ; Tue, 21 Aug 2018 15:59:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728174AbeHUTUD (ORCPT ); Tue, 21 Aug 2018 15:20:03 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:53978 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1727031AbeHUTUD (ORCPT ); Tue, 21 Aug 2018 15:20:03 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 1A7898076825; Tue, 21 Aug 2018 15:59:20 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-123-147.rdu2.redhat.com [10.10.123.147]) by smtp.corp.redhat.com (Postfix) with ESMTP id 29A212026D64; Tue, 21 Aug 2018 15:59:19 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 22/23] TPMLIB: Provide call for TPM_FlushSpecific From: David Howells To: denkenz@gmail.com, jarkko.sakkinen@linux.intel.com, jejb@linux.vnet.ibm.com Cc: keyrings@vger.kernel.org, linux-integrity@vger.kernel.org, tpmdd-devel@lists.sourceforge.net, linux-security-module@vger.kernel.org Date: Tue, 21 Aug 2018 16:59:18 +0100 Message-ID: <153486715863.13066.9507446322086735862.stgit@warthog.procyon.org.uk> In-Reply-To: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> References: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Tue, 21 Aug 2018 15:59:20 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Tue, 21 Aug 2018 15:59:20 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'dhowells@redhat.com' RCPT:'' Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP --- drivers/char/tpm/tpm-library.c | 31 +++++++++++++++++++++++++++++++ include/linux/tpm.h | 17 +++++++++++++++++ include/linux/tpm_command.h | 1 + 3 files changed, 49 insertions(+) diff --git a/drivers/char/tpm/tpm-library.c b/drivers/char/tpm/tpm-library.c index d279243ccc00..27e993f0b0b7 100644 --- a/drivers/char/tpm/tpm-library.c +++ b/drivers/char/tpm/tpm-library.c @@ -1110,6 +1110,37 @@ out: } EXPORT_SYMBOL_GPL(tpm_load_key2); +/** + * tpm_flush_specific - Tell the TPM to discard a handle and associated resources + * @chip: The chip to use + * @handle: The handle to discard + * @handle_type: The type of handle + */ +int tpm_flush_specific(struct tpm_chip *chip, + uint32_t handle, enum tpm_resource_type handle_type) +{ + struct tpm_buf *tb; + int ret; + + /* alloc some work space */ + tb = kmalloc(sizeof(*tb), GFP_KERNEL); + if (!tb) + return -ENOMEM; + + /* build and send the TPM request packet */ + INIT_BUF(tb); + store16(tb, TPM_TAG_RQU_COMMAND); + store32(tb, TPM_DATA_OFFSET + 8); + store32(tb, TPM_ORD_FLUSHSPECIFIC); + store32(tb, handle); + store32(tb, handle_type); + + ret = tpm_send_dump(chip, tb, "flushing handle"); + kfree(tb); + return ret; +} +EXPORT_SYMBOL_GPL(tpm_flush_specific); + /** * tpm_library_use - Tell the TPM library we want to make use of it * diff --git a/include/linux/tpm.h b/include/linux/tpm.h index 2be0decff93b..753ffd3799a1 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -109,6 +109,19 @@ enum tpm_entity_type { TPM_ET_RESERVED_HANDLE = 0x40, }; +enum tpm_resource_type { + TPM_RT_KEY = 0x00000001, + TPM_RT_AUTH = 0x00000002, + TPM_RT_HASH = 0x00000003, + TPM_RT_TRANS = 0x00000004, + TPM_RT_CONTEXT = 0x00000005, + TPM_RT_COUNTER = 0x00000006, + TPM_RT_DELEGATE = 0x00000007, + TPM_RT_DAA_TPM = 0x00000008, + TPM_RT_DAA_V0 = 0x00000009, + TPM_RT_DAA_V1 = 0x0000000a, +}; + struct tpm_buf { unsigned short len; unsigned short offset; @@ -154,4 +167,8 @@ extern int tpm_load_key2(struct tpm_chip *chip, const struct tpm_wrapped_key *wrapped_key, uint32_t *_key_handle); +extern int tpm_flush_specific(struct tpm_chip *chip, + uint32_t handle, + enum tpm_resource_type handle_type); + #endif diff --git a/include/linux/tpm_command.h b/include/linux/tpm_command.h index 211d4ce75f67..8b52447bbee3 100644 --- a/include/linux/tpm_command.h +++ b/include/linux/tpm_command.h @@ -30,6 +30,7 @@ enum tpm_ordinal { TPM_ORD_READPUBEK = 124, TPM_ORD_SAVESTATE = 152, TPM_ORD_STARTUP = 153, + TPM_ORD_FLUSHSPECIFIC = 186, }; /* Other constants */ From patchwork Tue Aug 21 15:59:25 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Howells X-Patchwork-Id: 10572005 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id F0F1D17E0 for ; Tue, 21 Aug 2018 15:59:30 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DFE732A989 for ; Tue, 21 Aug 2018 15:59:30 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D408B2A9AE; Tue, 21 Aug 2018 15:59:30 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 309362A9B1 for ; Tue, 21 Aug 2018 15:59:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728179AbeHUTUL (ORCPT ); Tue, 21 Aug 2018 15:20:11 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:59600 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1727031AbeHUTUL (ORCPT ); Tue, 21 Aug 2018 15:20:11 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id CF77340201CA; Tue, 21 Aug 2018 15:59:26 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-123-147.rdu2.redhat.com [10.10.123.147]) by smtp.corp.redhat.com (Postfix) with ESMTP id BF1DE2156701; Tue, 21 Aug 2018 15:59:25 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 23/23] TPM: Add an asymmetric key subtype for handling TPM-based keys From: David Howells To: denkenz@gmail.com, jarkko.sakkinen@linux.intel.com, jejb@linux.vnet.ibm.com Cc: keyrings@vger.kernel.org, linux-integrity@vger.kernel.org, tpmdd-devel@lists.sourceforge.net, linux-security-module@vger.kernel.org Date: Tue, 21 Aug 2018 16:59:25 +0100 Message-ID: <153486716525.13066.18042327896429419884.stgit@warthog.procyon.org.uk> In-Reply-To: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> References: <153486700916.13066.12870860668352070081.stgit@warthog.procyon.org.uk> User-Agent: StGit/unknown-version MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Tue, 21 Aug 2018 15:59:26 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Tue, 21 Aug 2018 15:59:26 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'dhowells@redhat.com' RCPT:'' Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Add an asymmetric key subtype for handling keys that have to be loaded into the TPM to be used. A key can be created by something like: keyctl add asymmetric "a" "tpm_create parent=40000000,095c2a76085f6aa9327c62f72a3d1348f62b99db keyauth=095c2a76085f6aa9327c62f72a3d1348f62b99db" @s where "parent=," and "keyauth=". The above will ask the TPM to create a key and return the TPM_KEY struct as a blob with the private key encrypted by the parent key (in the above case, the SRK). Signed-off-by: David Howells --- crypto/asymmetric_keys/Kconfig | 7 + crypto/asymmetric_keys/Makefile | 1 crypto/asymmetric_keys/tpm_key.c | 73 +++++++++++ crypto/asymmetric_keys/tpm_key.h | 19 +++ crypto/asymmetric_keys/tpm_key_parser.c | 212 +++++++++++++++++++++++++++++++ 5 files changed, 312 insertions(+) create mode 100644 crypto/asymmetric_keys/tpm_key.c create mode 100644 crypto/asymmetric_keys/tpm_key.h create mode 100644 crypto/asymmetric_keys/tpm_key_parser.c diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig index 4870f28403f5..97d1bb714617 100644 --- a/crypto/asymmetric_keys/Kconfig +++ b/crypto/asymmetric_keys/Kconfig @@ -67,4 +67,11 @@ config SIGNED_PE_FILE_VERIFICATION This option provides support for verifying the signature(s) on a signed PE binary. +config ASYMMETRIC_TPM_KEY_SUBTYPE + tristate "Asymmetric TPM-based public-key crypto algorithm subtype" + depends on TCG_TPM + help + This option provides support for TPM hardware-based asymmetric public + key type handling. + endif # ASYMMETRIC_KEY_TYPE diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile index e47fcd9ac5e8..690c16a517a9 100644 --- a/crypto/asymmetric_keys/Makefile +++ b/crypto/asymmetric_keys/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys.o asymmetric_keys-y := asymmetric_type.o signature.o obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o +obj-$(CONFIG_ASYMMETRIC_TPM_KEY_SUBTYPE) += tpm_key.o tpm_key_parser.o obj-$(CONFIG_PUBLIC_KEY_ALGO_RSA) += rsa.o # diff --git a/crypto/asymmetric_keys/tpm_key.c b/crypto/asymmetric_keys/tpm_key.c new file mode 100644 index 000000000000..bfddedc9db32 --- /dev/null +++ b/crypto/asymmetric_keys/tpm_key.c @@ -0,0 +1,73 @@ +/* In-TPM asymmetric public-key crypto subtype + * + * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#define pr_fmt(fmt) "TPK: "fmt +#include +#include +#include +#include +#include +#include +#include +#include "tpm_key.h" + +MODULE_LICENSE("GPL"); + +/* + * Provide a part of a description of the key for /proc/keys. + */ +static void tpm_key_describe(const struct key *asymmetric_key, + struct seq_file *m) +{ + struct tpm_asymmetric_key *key = asymmetric_key->payload.data; + struct tpm_wrapped_key *wrap; + + if (key && key->wrapped_key) { + wrap = key->wrapped_key; + seq_printf(m, "TPM.RSA %*phN", + wrap->pubkey_len, wrap->data + wrap->pubkey_offset); + } +} + +/* + * Destroy a TPM-based key. + */ +static void tpm_key_destroy(void *payload) +{ + struct tpm_asymmetric_key *key = payload; + + if (key) { + kfree(key->wrapped_key); + kfree(key); + tpm_library_unuse(); + } +} + +/* + * Verify a signature using a TPM-based key. + */ +static int tpm_key_verify_signature(const struct key *key, + const struct public_key_signature *sig) +{ + return -EOPNOTSUPP; +} + +/* + * Public key algorithm asymmetric key subtype + */ +struct asymmetric_key_subtype tpm_key_subtype = { + .owner = THIS_MODULE, + .name = "tpm_key", + .describe = tpm_key_describe, + .destroy = tpm_key_destroy, + .verify_signature = tpm_key_verify_signature, +}; +EXPORT_SYMBOL_GPL(tpm_key_subtype); diff --git a/crypto/asymmetric_keys/tpm_key.h b/crypto/asymmetric_keys/tpm_key.h new file mode 100644 index 000000000000..712221fee874 --- /dev/null +++ b/crypto/asymmetric_keys/tpm_key.h @@ -0,0 +1,19 @@ +/* TPM-based public key algorithm internals + * + * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +struct tpm_asymmetric_key { + struct tpm_wrapped_key *wrapped_key; + u32 parent_tpm_handle; + u8 parent_authdata[TPM_DIGEST_SIZE]; + u8 key_authdata[TPM_DIGEST_SIZE]; +}; + +extern struct asymmetric_key_subtype tpm_key_subtype; diff --git a/crypto/asymmetric_keys/tpm_key_parser.c b/crypto/asymmetric_keys/tpm_key_parser.c new file mode 100644 index 000000000000..efb53172b43d --- /dev/null +++ b/crypto/asymmetric_keys/tpm_key_parser.c @@ -0,0 +1,212 @@ +/* Instantiate a TPM key. + * + * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ +#define DEBUG +#define pr_fmt(fmt) "TPKP: "fmt +#include +#include +#include +#include +#include +#include +#include +#include +#include "asymmetric_keys.h" +#include "tpm_key.h" + + +enum tpm_key_create_token { + opt_crt_err = -1, + opt_crt_parent, + opt_crt_keyauth, +}; + +static const match_table_t tpm_key_create_tokens = { + { opt_crt_parent, "parent=%x,%s"}, + { opt_crt_keyauth, "keyauth=%s"}, + { opt_crt_err, NULL} +}; + +/* + * Attempt to parse a key creation request. + */ +static int tpm_key_create(struct tpm_asymmetric_key *key, char *data) +{ + enum tpm_key_create_token token; + struct tpm_chip *chip; + unsigned long tmp, got = 0; + substring_t args[MAX_OPT_ARGS]; + uint32_t key_handle; + char *p; + int ret; + + pr_devel("==>%s(,%s)\n", __func__, data); + + while ((p = strsep(&data, " \t"))) { + if (*p == '\0' || *p == ' ' || *p == '\t') + continue; + token = match_token(p, tpm_key_create_tokens, args); + switch (token) { + case opt_crt_parent: + pr_devel("parent %ld %ld\n", + args[0].to - args[0].from, + args[1].to - args[1].from); + *args[0].to = 0; + ret = kstrtoul(args[0].from, 16, &tmp); + if (ret < 0) { + pr_devel("bad parent handle\n"); + return -EINVAL; + } + key->parent_tpm_handle = tmp; + if (args[1].to - args[1].from != TPM_DIGEST_SIZE * 2) { + pr_devel("parent auth wrong size\n"); + return -EINVAL; + } + if (hex2bin(key->parent_authdata, args[1].from, + TPM_DIGEST_SIZE) < 0) { + pr_devel("parent auth bad hex\n"); + return -EINVAL; + } + break; + + case opt_crt_keyauth: + pr_devel("keyauth\n"); + if (args[1].to - args[1].from != TPM_DIGEST_SIZE * 2) + return -EINVAL; + if (hex2bin(key->parent_authdata, args[1].from, + TPM_DIGEST_SIZE) < 0) + return -EINVAL; + break; + + case opt_crt_err: + pr_devel("Unknown token %s\n", p); + return -EINVAL; + } + got |= 1 << token; + } + + if ((got & 3) != 3) { + pr_devel("Missing mandatory args\n"); + return -EINVAL; + } + + chip = tpm_chip_find_get(TPM_ANY_NUM); + if (!chip) + return -ENODEV; + + /* Create a key and retrieve the partially encrypted blob. */ + ret = tpm_create_wrap_key(chip, TPM_ET_SRK, key->parent_tpm_handle, + key->parent_authdata, + key->key_authdata, + NULL, + &key->wrapped_key); + if (ret == -EBADMSG) + ret = -EIO; + + /* Attempt to load the key back as a check */ + ret = tpm_load_key2(chip, TPM_ET_SRK, key->parent_tpm_handle, + key->parent_authdata, key->wrapped_key, + &key_handle); + if (ret != 0) { + pr_devel("Couldn't load key back\n"); + goto out; + } + + ret = tpm_flush_specific(chip, key_handle, TPM_RT_KEY); + if (ret != 0) + pr_devel("Couldn't flush key handle\n"); + +out: + tpm_chip_put(chip); + pr_devel("<==%s() = %d\n", __func__, ret); + return ret; +} + +/* + * Attempt to parse a data blob for a key as a TPM key specification. + * + * We expect one of the following in the prep data: + * + * tpm_create parent=, keyauth= [options...] + * tpm_load parent=, data= [options...] + */ +static int tpm_key_preparse(struct key_preparsed_payload *prep) +{ + struct tpm_asymmetric_key *key; + char *data; + int ret; + + pr_devel("==>%s()\n", __func__); + + ret = tpm_library_use(); + if (ret < 0) + goto out; + + ret = -ENOMEM; + key = kzalloc(sizeof(*key), GFP_KERNEL); + if (!key) + goto out_free_tpmlib; + data = kmalloc(prep->datalen + 1, GFP_KERNEL); + if (!data) + goto out_free_key; + + memcpy(data, prep->data, prep->datalen); + data[prep->datalen] = 0; + if (memcmp(data, "tpm_create ", 11) == 0) { + ret = tpm_key_create(key, data + 11); + } else { + ret = -EBADMSG; + goto out_free_data; + } + + /* We're pinning the module by being linked against it */ + __module_get(tpm_key_subtype.owner); + prep->type_data[0] = &tpm_key_subtype; + //prep->type_data[1] = kids; + prep->payload[0] = key; + //prep->description = desc; + prep->quotalen = 100; + key = NULL; + tpm_library_use(); + +out_free_data: + kfree(data); +out_free_key: + kfree(key); +out_free_tpmlib: + tpm_library_unuse(); +out: + return ret; +} + +static struct asymmetric_key_parser tpm_key_parser = { + .owner = THIS_MODULE, + .name = "tpm", + .parse = tpm_key_preparse, +}; + +/* + * Module stuff + */ +static int __init tpm_key_init(void) +{ + return register_asymmetric_key_parser(&tpm_key_parser); +} + +static void __exit tpm_key_exit(void) +{ + unregister_asymmetric_key_parser(&tpm_key_parser); +} + +module_init(tpm_key_init); +module_exit(tpm_key_exit); + +MODULE_DESCRIPTION("TPM key parser"); +MODULE_LICENSE("GPL");