qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: "Michael S. Tsirkin" <mst@redhat.com>
To: Stefan Berger <stefanb@linux.vnet.ibm.com>
Cc: chrisw@redhat.com, anbang.ruan@cs.ox.ac.uk,
	qemu-devel@nongnu.org, rrelyea@redhat.com, alevy@redhat.com,
	andreas.niederl@iaik.tugraz.at, serge@hallyn.com
Subject: Re: [Qemu-devel] [PATCH V8 14/14] Allow to provide inital TPM state
Date: Thu, 1 Sep 2011 21:10:25 +0300	[thread overview]
Message-ID: <20110901181024.GJ10989@redhat.com> (raw)
In-Reply-To: <20110831143625.419705972@linux.vnet.ibm.com>

On Wed, Aug 31, 2011 at 10:36:05AM -0400, Stefan Berger wrote:
> 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>

I am guessing we get the base64 format from tpmlib?

> ---
>  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;
> +

This hardcodes assumption of a single backend.

>  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;
> +        }

Do we really have to hand-craft file reading?
How large is TPMPROP_TPM_MAX_NV_SPACE?
If not too large, we can just allocate that
and do a single fread call?

Or, we rely on glib now - can we use 
g_io_channel_read_to_end () or something like that?



> +        /* have it written into the BlockStorage */
> +        rc = tpm_builtin_nvram_storedata(*data, *length, tpm_number, name);

What if that backend is compiled-out?
link will fail?

> +        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;
> +            }
> +        }
> +    }
> +

Separate options for fd and for file mode would be better.

>      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 */ }
>      },
>  };

I think description should document the magic bin:/base64: etc strings,
or better get rid of them.

> 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.

The command line is non standard.  E.g. what if the path starts with fd?

> +@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
> 

  reply	other threads:[~2011-09-01 18:10 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 ` [Qemu-devel] [PATCH V8 14/14] Allow to provide inital TPM state Stefan Berger
2011-09-01 18:10   ` Michael S. Tsirkin [this message]
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=20110901181024.GJ10989@redhat.com \
    --to=mst@redhat.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 \
    --cc=stefanb@linux.vnet.ibm.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).