qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Stefan Berger <stefanb@linux.vnet.ibm.com>
To: stefanb@linux.vnet.ibm.com, qemu-devel@nongnu.org
Cc: chrisw@redhat.com, anbang.ruan@cs.ox.ac.uk, rrelyea@redhat.com,
	alevy@redhat.com, andreas.niederl@iaik.tugraz.at,
	serge@hallyn.com
Subject: [Qemu-devel] [PATCH V8 14/14] Allow to provide inital TPM state
Date: Wed, 31 Aug 2011 10:36:05 -0400	[thread overview]
Message-ID: <20110831143625.419705972@linux.vnet.ibm.com> (raw)
In-Reply-To: 20110831143551.127339744@linux.vnet.ibm.com

[-- Attachment #1: qemu_tpm_initstate.diff --]
[-- Type: text/plain, Size: 10106 bytes --]

This patch adds a -tpm ...,initstate=...,... command line option to the
TPM's existing options and enables the TPM to be initialized with an
existing state blob. This in turn allows us to simulate TPM manufacturing
and equip the TPM with an endorsement key, certificates and initialize its
NVRAM areas etc.. This step is typically done during manufacturng of the TPM
and/or the (physical) machine.

The initial state can be passed either as file or via a file descriptor. The
encoding of the state can either be binary or in form of a base64-encoded
blob surrounded by tags indicating the start and end.

The intial state can be produced through a yet-to-be-published tpm-authoring
tool.

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>

---
 hw/tpm_builtin.c |  123 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 qemu-config.c    |   12 +++++
 qemu-options.hx  |   40 ++++++++++++++++-
 3 files changed, 172 insertions(+), 3 deletions(-)

Index: qemu-git/hw/tpm_builtin.c
===================================================================
--- qemu-git.orig/hw/tpm_builtin.c
+++ qemu-git/hw/tpm_builtin.c
@@ -170,9 +170,16 @@ static struct enckey {
     AES_KEY tpm_dec_key;
 } enckey;
 
+static int tpm_initstatefd = -1;
+static bool tpm_initstate_bin;
+
 static int tpm_builtin_load_sized_data_from_bs(BlockDriverState *bs,
                                                enum BSEntryType be,
                                                TPMSizedBuffer *tsb);
+static TPM_RESULT tpm_builtin_get_initial_state(unsigned char **data,
+                                                uint32_t *length,
+                                                size_t tpm_number,
+                                                const char *name);
 
 
 
@@ -1269,7 +1276,7 @@ static TPM_RESULT tpm_builtin_nvram_load
         *length = permanent_state.size;
 
         if (*length == 0) {
-            rc = TPM_RETRY;
+            rc = tpm_builtin_get_initial_state(data, length, tpm_number, name);
         } else {
             /* keep a copy of the last permanent state */
             rc = TPM_Malloc(data, *length);
@@ -1452,6 +1459,94 @@ static TPM_RESULT tpm_builtin_io_getphys
 }
 
 
+static TPM_RESULT tpm_builtin_get_initial_state(unsigned char **data,
+                                                uint32_t *length,
+                                                size_t tpm_number,
+                                                const char *name)
+{
+    TPM_RESULT rc = TPM_RETRY;
+    uint32_t allocated = 0;
+    int len, flags;
+    unsigned char buf[1024];
+    unsigned char *result = NULL;
+    size_t result_len;
+
+    if (tpm_initstatefd >= 0) {
+        *data = NULL;
+        *length = 0;
+
+        flags = fcntl(tpm_initstatefd, F_GETFL);
+        if (flags < 0 ||
+            fcntl(tpm_initstatefd, F_SETFL, flags & ~O_NONBLOCK) < 0) {
+            return TPM_FAIL;
+        }
+
+        while (TRUE) {
+            len = read(tpm_initstatefd, buf, sizeof(buf));
+
+            if (len > 0) {
+                if (len > allocated - *length) {
+                    allocated = *length + len + 1024;
+                    if (TPM_Realloc(data, allocated) != TPM_SUCCESS) {
+                        goto err_exit;
+                    }
+                }
+                memcpy(&(*data)[*length], buf, len);
+                *length += len;
+                (*data)[*length] = 0;
+            } else if (len == 0) {
+                rc = TPM_SUCCESS;
+                break;
+            } else if (len < 0) {
+                if (errno == EINTR) {
+                    continue;
+                }
+                goto err_exit;
+            }
+        }
+
+        if (*data == NULL) {
+            /* nothing read */
+            rc = TPM_FAIL;
+            goto err_exit;
+        }
+
+        if (!tpm_initstate_bin) {
+            if (TPMLIB_DecodeBlob((char *)*data, TPMLIB_BLOB_TYPE_INITSTATE,
+                                  &result, &result_len) != TPM_SUCCESS) {
+                goto err_exit;
+            }
+            TPM_Free(*data);
+            *data = result;
+            *length = result_len;
+            result = NULL;
+        }
+        /* sanity check for the size of the blob */
+        if (*length > tpmlib_get_prop(TPMPROP_TPM_MAX_NV_SPACE)) {
+            goto err_exit;
+        }
+        /* have it written into the BlockStorage */
+        rc = tpm_builtin_nvram_storedata(*data, *length, tpm_number, name);
+        if (rc != TPM_SUCCESS) {
+            goto err_exit;
+        }
+    }
+
+norm_exit:
+    close(tpm_initstatefd);
+    tpm_initstatefd = -1;
+
+    return rc;
+
+err_exit:
+    TPM_Free(*data);
+    *data = NULL;
+    *length = 0;
+    TPM_Free(result);
+
+    goto norm_exit;
+}
+
 /*****************************************************************/
 
 
@@ -1748,6 +1843,7 @@ static TPMBackend *tpm_builtin_create(Qe
     const char *value;
     unsigned char keyvalue[256/8];
     int keysize = sizeof(keyvalue);
+    unsigned int offset;
 
     driver = g_malloc(sizeof(TPMBackend));
     if (!driver) {
@@ -1801,6 +1897,28 @@ static TPMBackend *tpm_builtin_create(Qe
         enckey.enctype = BS_DIR_ENCTYPE_NONE;
     }
 
+    value = qemu_opt_get(opts, "initstate");
+    if (value) {
+        offset = 0;
+
+        if (!strncmp(value, "bin:", 4)) {
+            tpm_initstate_bin = true;
+            offset = 4;
+        } else if (!strncmp(value, "base64:", 7)) {
+            tpm_initstate_bin = false;
+            offset = 7;
+        }
+
+        if (sscanf(&value[offset], "fd:%d", &tpm_initstatefd) != 1) {
+            tpm_initstatefd = open(&value[offset], O_RDONLY);
+            if (tpm_initstatefd < 0) {
+                fprintf(stderr, "tpm: could not open file '%s' for reading.\n",
+                        value);
+                goto err_exit;
+            }
+        }
+    }
+
     return driver;
 
 err_exit:
@@ -1816,6 +1934,9 @@ static void tpm_builtin_destroy(TPMBacke
     g_free(driver->id);
     g_free(driver->model);
     g_free(driver);
+
+    close(tpm_initstatefd);
+    tpm_initstatefd = -1;
 }
 
 
Index: qemu-git/qemu-config.c
===================================================================
--- qemu-git.orig/qemu-config.c
+++ qemu-git/qemu-config.c
@@ -527,6 +527,12 @@ static QemuOptsList qemu_tpmdev_opts = {
             .type = QEMU_OPT_STRING,
             .help = "Data encryption key",
         },
+        {
+            .name = "initstate",
+            .type = QEMU_OPT_STRING,
+            .help = "File or file descriptor for reading initial TPM state "
+                    "from",
+        },
         { /* end of list */ }
     },
 };
@@ -556,6 +562,12 @@ static QemuOptsList qemu_tpm_opts = {
             .type = QEMU_OPT_STRING,
             .help = "Data encryption key",
         },
+        {
+            .name = "initstate",
+            .type = QEMU_OPT_STRING,
+            .help = "File or file descriptor for reading initial TPM state "
+                    "from",
+        },
         { /* end of list */ }
     },
 };
Index: qemu-git/qemu-options.hx
===================================================================
--- qemu-git.orig/qemu-options.hx
+++ qemu-git/qemu-options.hx
@@ -1767,8 +1767,10 @@ DEFHEADING(TPM device options:)
 DEF("tpm", HAS_ARG, QEMU_OPTION_tpm, \
     "" \
     "-tpm builtin,path=<path>[,model=<model>][,key=<aes key>]\n" \
+    "     [,initstate=[bin:|base64:]fd:<fd>|<path>]\n" \
     "                enable a builtin TPM with state in file in path\n" \
     "                and encrypt the TPM's state with the given AES key\n" \
+    "                initstate= path to initial state of TPM; default is base64\n" \
     "-tpm null       enable a TPM null driver that responds with a fault\n" \
     "                message to every TPM request\n" \
     "-tpm model=?    to list available TPM device models\n" \
@@ -1800,7 +1802,7 @@ Use ? to print all available TPM backend
 qemu -tpmdev ?
 @end example
 
-@item -tpmdev builtin ,id=@var{id}, path=@var{path} [,key=@var{key}]
+@item -tpmdev builtin ,id=@var{id}, path=@var{path} [,key=@var{key}] [,initstate=@var{path}]
 
 Creates an instance of the built-in TPM.
 
@@ -1830,6 +1832,40 @@ using AES-CBC encryption scheme supply t
 -tpmdev builtin,id=tpm0,path=<path_to_qcow2>,key=aes-cbc:0x1234567890abcdef01234567890abcdef -device tpm-tis,tpmdev=tpm0
 @end example
 
+@option{initstate} specifies the path to a file containing the initial
+state of the TPM. It can be used to provide the TPM with an EK and certificates
+for the EK, TPM and Platform. Since the file contains binary data that
+have to conform to the TPM's layout of data, it must have been created using
+an approriate authoring tool.
+
+The initstate option allows to provide a binary state blob or one that is
+encode in base 64. The base64-encode state blob must have the format
+
+@example
+-----BEGIN INITSTATE-----
+<base 64 encoded state>
+-----END INITSTATE-----
+@end example
+
+The initstate option is only effective when Qemu is started with blank
+state.
+
+The initstate option supports several formats:
+
+@table @option
+ @item  [base64:]<path_to_blob>
+ Provide the path to the TPM's initial state blob in base64 format.
+ @item  bin:<path to blob>
+ Provide the path to the TPM's initial state blob in binary format.
+ @item  [base64:]fd:<fd>
+ Provide the base64 formatted initial state via a file descriptor to read from.
+ @item  bin:fd:<fd>
+ Provide the binary initial state via a file descriptor to read from.
+@end table
+
+@option{initstate} is optional.
+
+
 @item -tpmdev null
 
 Creates an instance of a TPM null driver that responds to every command
@@ -1840,7 +1876,7 @@ with a fault message.
 The short form of a TPM device option is:
 @table @option
 
-@item -tpm @var{backend-type}, path=@var{path} [,model=@var{model}] [,key=@var{key}]
+@item -tpm @var{backend-type}, path=@var{path} [,model=@var{model}] [,key=@var{key}] [,initstate=@var{path}]
 @findex -tpm
 
 @option{model} specifies the device model. The default device model is a

  parent reply	other threads:[~2011-08-31 14:36 UTC|newest]

Thread overview: 75+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-08-31 14:35 [Qemu-devel] [PATCH V8 00/14] Qemu Trusted Platform Module (TPM) integration Stefan Berger
2011-08-31 14:35 ` [Qemu-devel] [PATCH V8 01/14] Support for TPM command line options Stefan Berger
2011-09-01 17:14   ` Michael S. Tsirkin
2011-09-02  1:01     ` Stefan Berger
2011-09-04 16:29       ` Michael S. Tsirkin
2011-09-04 16:50       ` Michael S. Tsirkin
2011-09-01 18:14   ` Michael S. Tsirkin
2011-09-02  1:02     ` Stefan Berger
2011-08-31 14:35 ` [Qemu-devel] [PATCH V8 02/14] Add TPM (frontend) hardware interface (TPM TIS) to Qemu Stefan Berger
2011-09-09 19:28   ` Paul Moore
2011-08-31 14:35 ` [Qemu-devel] [PATCH V8 03/14] Add persistent state handling to TPM TIS frontend driver Stefan Berger
2011-09-01 17:20   ` Michael S. Tsirkin
2011-09-02  1:12     ` Stefan Berger
2011-09-09 21:13   ` Paul Moore
2011-09-11 16:45     ` Stefan Berger
2011-09-12 21:16       ` Paul Moore
2011-09-12 23:37         ` Stefan Berger
2011-09-13 12:13           ` Paul Moore
2011-08-31 14:35 ` [Qemu-devel] [PATCH V8 04/14] Add tpm_tis driver to build process Stefan Berger
2011-09-01 17:23   ` Michael S. Tsirkin
2011-09-02  1:16     ` Stefan Berger
2011-08-31 14:35 ` [Qemu-devel] [PATCH V8 05/14] Add a debug register Stefan Berger
2011-08-31 14:35 ` [Qemu-devel] [PATCH V8 06/14] Add a TPM backend skeleton implementation Stefan Berger
2011-08-31 14:35 ` [Qemu-devel] [PATCH V8 07/14] Implementation of the libtpms-based backend Stefan Berger
2011-09-01 17:27   ` Michael S. Tsirkin
2011-09-02  1:24     ` Stefan Berger
2011-09-04 16:27       ` Michael S. Tsirkin
2011-08-31 14:35 ` [Qemu-devel] [PATCH V8 08/14] Introduce file lock for the block layer Stefan Berger
2011-09-01 17:32   ` Michael S. Tsirkin
2011-09-02  1:53     ` Stefan Berger
2011-09-04 19:32       ` Michael S. Tsirkin
2011-09-06 23:55         ` Stefan Berger
2011-09-07 11:18           ` Michael S. Tsirkin
2011-09-07 13:06             ` Stefan Berger
2011-09-07 13:16               ` Michael S. Tsirkin
2011-09-07 13:56                 ` Stefan Berger
2011-09-07 14:10                   ` Michael S. Tsirkin
2011-09-07 14:25                     ` Stefan Berger
2011-09-07 14:35                       ` Michael S. Tsirkin
2011-09-07 15:06                         ` Stefan Berger
2011-09-07 15:16                           ` Michael S. Tsirkin
2011-09-07 16:08                             ` Stefan Berger
2011-09-07 18:49                               ` Michael S. Tsirkin
2011-09-08  0:31                                 ` Stefan Berger
2011-09-08 10:36                                   ` Michael S. Tsirkin
2011-08-31 14:36 ` [Qemu-devel] [PATCH V8 09/14] Add block storage support for libtpms based TPM backend Stefan Berger
2011-08-31 14:36 ` [Qemu-devel] [PATCH V8 10/14] Encrypt state blobs using AES CBC encryption Stefan Berger
2011-09-01 19:26   ` Michael S. Tsirkin
2011-09-02  2:23     ` Stefan Berger
2011-09-04 16:58       ` Michael S. Tsirkin
2011-09-07  0:32         ` Stefan Berger
2011-09-07 11:59           ` Michael S. Tsirkin
2011-09-07 18:55       ` Michael S. Tsirkin
2011-09-08  0:16         ` Stefan Berger
2011-09-08 10:32           ` Michael S. Tsirkin
2011-09-08 12:11             ` Stefan Berger
2011-09-08 13:16               ` Michael S. Tsirkin
2011-09-08 15:27                 ` Stefan Berger
2011-08-31 14:36 ` [Qemu-devel] [PATCH V8 11/14] Experimental support for block migrating TPMs state Stefan Berger
2011-08-31 14:36 ` [Qemu-devel] [PATCH V8 12/14] Support for taking measurements when kernel etc. are passed to Qemu Stefan Berger
2011-08-31 14:36 ` [Qemu-devel] [PATCH V8 13/14] Add a TPM backend null driver implementation Stefan Berger
2011-09-01 17:40   ` Michael S. Tsirkin
2011-09-02  2:41     ` Stefan Berger
2011-09-04 16:42       ` Michael S. Tsirkin
2011-08-31 14:36 ` Stefan Berger [this message]
2011-09-01 18:10   ` [Qemu-devel] [PATCH V8 14/14] Allow to provide inital TPM state Michael S. Tsirkin
2011-09-01 19:01     ` Michael S. Tsirkin
2011-09-02  3:00     ` Stefan Berger
2011-09-04 16:38       ` Michael S. Tsirkin
2011-09-07  2:45         ` Stefan Berger
2011-09-07 11:23           ` Michael S. Tsirkin
2011-09-07 13:51             ` Stefan Berger
2011-09-07 13:57               ` Michael S. Tsirkin
2011-09-01 18:12 ` [Qemu-devel] [PATCH V8 00/14] Qemu Trusted Platform Module (TPM) integration Michael S. Tsirkin
2011-09-02  3:02   ` Stefan Berger

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20110831143625.419705972@linux.vnet.ibm.com \
    --to=stefanb@linux.vnet.ibm.com \
    --cc=alevy@redhat.com \
    --cc=anbang.ruan@cs.ox.ac.uk \
    --cc=andreas.niederl@iaik.tugraz.at \
    --cc=chrisw@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=rrelyea@redhat.com \
    --cc=serge@hallyn.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).