diff mbox series

tpm: add backend for mssim

Message ID 4780481659602f92fffacac66e7dca41ad2787c4.camel@linux.ibm.com (mailing list archive)
State New, archived
Headers show
Series tpm: add backend for mssim | expand

Commit Message

James Bottomley Dec. 10, 2022, 5:10 p.m. UTC
The Microsoft Simulator (mssim) is the reference emulation platform
for the TCG TPM 2.0 specification.

https://github.com/Microsoft/ms-tpm-20-ref.git

It exports a fairly simple network socket baset protocol on two
sockets, one for command (default 2321) and one for control (default
2322).  This patch adds a simple backend that can speak the mssim
protocol over the network.  It also allows the host, and two ports to
be specified on the qemu command line.  The benefits are twofold:
firstly it gives us a backend that actually speaks a standard TPM
emulation protocol instead of the linux specific TPM driver format of
the current emulated TPM backend and secondly, using the microsoft
protocol, the end point of the emulator can be anywhere on the
network, facilitating the cloud use case where a central TPM service
can be used over a control network.

The implementation does basic control commands like power off/on, but
doesn't implement cancellation or startup.  The former because
cancellation is pretty much useless on a fast operating TPM emulator
and the latter because this emulator is designed to be used with OVMF
which itself does TPM startup and I wanted to validate that.

To run this, simply download an emulator based on the MS specification
(package ibmswtpm2 on openSUSE) and run it, then add these two lines
to the qemu command and it will use the emulator.

    -tpmdev mssim,id=tpm0 \
    -device tpm-crb,tpmdev=tpm0 \

to use a remote emulator replace the first line with

    -tpmdev mssim,it=tpm0,host=remote.host,port=4455,ctrl=4457 \

tpm-tis also works as the backend.

Signed-off-by: James Bottomley <jejb@linux.ibm.com>
---
 backends/tpm/Kconfig     |   5 +
 backends/tpm/meson.build |   1 +
 backends/tpm/tpm_mssim.c | 266 +++++++++++++++++++++++++++++++++++++++
 backends/tpm/tpm_mssim.h |  43 +++++++
 monitor/hmp-cmds.c       |   6 +
 qapi/tpm.json            |  35 +++++-
 6 files changed, 353 insertions(+), 3 deletions(-)
 create mode 100644 backends/tpm/tpm_mssim.c
 create mode 100644 backends/tpm/tpm_mssim.h

Comments

Stefan Berger Dec. 12, 2022, 1:43 p.m. UTC | #1
On 12/10/22 12:10, James Bottomley wrote:
> The Microsoft Simulator (mssim) is the reference emulation platform
> for the TCG TPM 2.0 specification.
> 
> https://github.com/Microsoft/ms-tpm-20-ref.git
> 
> It exports a fairly simple network socket baset protocol on two

baset -> based.

> sockets, one for command (default 2321) and one for control (default
> 2322).  This patch adds a simple backend that can speak the mssim
> protocol over the network.  It also allows the host, and two ports to
> be specified on the qemu command line.  The benefits are twofold:
> firstly it gives us a backend that actually speaks a standard TPM
> emulation protocol instead of the linux specific TPM driver format of
> the current emulated TPM backend and secondly, using the microsoft
> protocol, the end point of the emulator can be anywhere on the
> network, facilitating the cloud use case where a central TPM service
> can be used over a control network.
> 
> The implementation does basic control commands like power off/on, but
> doesn't implement cancellation or startup.  The former because
> cancellation is pretty much useless on a fast operating TPM emulator
> and the latter because this emulator is designed to be used with OVMF
> which itself does TPM startup and I wanted to validate that.

How did you implement VM suspend/resume and snapshotting support?

    Stefan

> 
> To run this, simply download an emulator based on the MS specification
> (package ibmswtpm2 on openSUSE) and run it, then add these two lines
> to the qemu command and it will use the emulator.
> 
>      -tpmdev mssim,id=tpm0 \
>      -device tpm-crb,tpmdev=tpm0 \
> 
> to use a remote emulator replace the first line with
> 
>      -tpmdev mssim,it=tpm0,host=remote.host,port=4455,ctrl=4457 \
> 
> tpm-tis also works as the backend.
> 
> Signed-off-by: James Bottomley <jejb@linux.ibm.com>
> ---
>   backends/tpm/Kconfig     |   5 +
>   backends/tpm/meson.build |   1 +
>   backends/tpm/tpm_mssim.c | 266 +++++++++++++++++++++++++++++++++++++++
>   backends/tpm/tpm_mssim.h |  43 +++++++
>   monitor/hmp-cmds.c       |   6 +
>   qapi/tpm.json            |  35 +++++-
>   6 files changed, 353 insertions(+), 3 deletions(-)
>   create mode 100644 backends/tpm/tpm_mssim.c
>   create mode 100644 backends/tpm/tpm_mssim.h
> 
> diff --git a/backends/tpm/Kconfig b/backends/tpm/Kconfig
> index 5d91eb89c2..d6d6fa53e9 100644
> --- a/backends/tpm/Kconfig
> +++ b/backends/tpm/Kconfig
> @@ -12,3 +12,8 @@ config TPM_EMULATOR
>       bool
>       default y
>       depends on TPM_BACKEND
> +
> +config TPM_MSSIM
> +    bool
> +    default y
> +    depends on TPM_BACKEND
> diff --git a/backends/tpm/meson.build b/backends/tpm/meson.build
> index 7f2503f84e..c7c3c79125 100644
> --- a/backends/tpm/meson.build
> +++ b/backends/tpm/meson.build
> @@ -3,4 +3,5 @@ if have_tpm
>     softmmu_ss.add(files('tpm_util.c'))
>     softmmu_ss.add(when: 'CONFIG_TPM_PASSTHROUGH', if_true: files('tpm_passthrough.c'))
>     softmmu_ss.add(when: 'CONFIG_TPM_EMULATOR', if_true: files('tpm_emulator.c'))
> +  softmmu_ss.add(when: 'CONFIG_TPM_MSSIM', if_true: files('tpm_mssim.c'))
>   endif
> diff --git a/backends/tpm/tpm_mssim.c b/backends/tpm/tpm_mssim.c
> new file mode 100644
> index 0000000000..6864b1fbc0
> --- /dev/null
> +++ b/backends/tpm/tpm_mssim.c
> @@ -0,0 +1,266 @@
> +/*
> + * Emulator TPM driver which connects over the mssim protocol
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + *
> + * Copyright (c) 2022
> + * Author: James Bottomley <jejb@linux.ibm.com>
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/error-report.h"
> +#include "qemu/sockets.h"
> +
> +#include "qapi/clone-visitor.h"
> +#include "qapi/qapi-visit-tpm.h"
> +
> +#include "io/channel-socket.h"
> +
> +#include "sysemu/tpm_backend.h"
> +#include "sysemu/tpm_util.h"
> +
> +#include "qom/object.h"
> +
> +#include "tpm_int.h"
> +#include "tpm_mssim.h"
> +
> +#define ERROR_PREFIX "TPM mssim Emulator: "
> +
> +#define TYPE_TPM_MSSIM "tpm-mssim"
> +OBJECT_DECLARE_SIMPLE_TYPE(TPMmssim, TPM_MSSIM)
> +
> +struct TPMmssim {
> +    TPMBackend parent;
> +
> +    TPMmssimOptions opts;
> +
> +    QIOChannel *cmd_qc, *ctrl_qc;
> +};
> +
> +static int tpm_send_ctrl(TPMmssim *t, uint32_t cmd, Error **errp)
> +{
> +    int ret;
> +
> +    cmd = htonl(cmd);
> +    ret = qio_channel_write_all(t->ctrl_qc, (char *)&cmd, sizeof(cmd), errp);
> +    if (ret != 0)
> +        return ret;
> +    ret = qio_channel_read_all(t->ctrl_qc, (char *)&cmd, sizeof(cmd), errp);
> +    if (ret != 0)
> +        return ret;
> +    if (cmd != 0) {
> +        error_setg(errp, ERROR_PREFIX "Incorrect ACK recieved on control channel 0x%x\n", cmd);
> +        return -1;
> +    }
> +    return 0;
> +}
> +
> +static void tpm_mssim_instance_init(Object *obj)
> +{
> +}
> +
> +static void tpm_mssim_instance_finalize(Object *obj)
> +{
> +    TPMmssim *t = TPM_MSSIM(obj);
> +
> +    tpm_send_ctrl(t, TPM_SIGNAL_POWER_OFF, NULL);
> +
> +    object_unref(OBJECT(t->ctrl_qc));
> +    object_unref(OBJECT(t->cmd_qc));
> +}
> +
> +static void tpm_mssim_cancel_cmd(TPMBackend *tb)
> +{
> +        return;
> +}
> +
> +static TPMVersion tpm_mssim_get_version(TPMBackend *tb)
> +{
> +    return TPM_VERSION_2_0;
> +}
> +
> +static size_t tpm_mssim_get_buffer_size(TPMBackend *tb)
> +{
> +    /* TCG standard profile max buffer size */
> +    return 4096;
> +}
> +
> +static TpmTypeOptions *tpm_mssim_get_opts(TPMBackend *tb)
> +{
> +    TPMmssim *t = TPM_MSSIM(tb);
> +    TpmTypeOptions *opts = g_new0(TpmTypeOptions, 1);
> +
> +    opts->type = TPM_TYPE_MSSIM;
> +    opts->u.mssim.data = QAPI_CLONE(TPMmssimOptions, &t->opts);
> +
> +    return opts;
> +}
> +
> +static void tpm_mssim_handle_request(TPMBackend *tb, TPMBackendCmd *cmd,
> +                                     Error **errp)
> +{
> +    TPMmssim *t = TPM_MSSIM(tb);
> +    uint32_t header, len;
> +    uint8_t locality = cmd->locty;
> +    struct iovec iov[4];
> +    int ret;
> +
> +    header = htonl(TPM_SEND_COMMAND);
> +    len = htonl(cmd->in_len);
> +
> +    iov[0].iov_base = &header;
> +    iov[0].iov_len = sizeof(header);
> +    iov[1].iov_base = &locality;
> +    iov[1].iov_len = sizeof(locality);
> +    iov[2].iov_base = &len;
> +    iov[2].iov_len = sizeof(len);
> +    iov[3].iov_base = (void *)cmd->in;
> +    iov[3].iov_len = cmd->in_len;
> +
> +    ret = qio_channel_writev_all(t->cmd_qc, iov, 4, errp);
> +    if (ret != 0)
> +        goto fail;
> +
> +    ret = qio_channel_read_all(t->cmd_qc, (char *)&len, sizeof(len), errp);
> +    if (ret != 0)
> +        goto fail;
> +    len = ntohl(len);
> +    if (len > cmd->out_len) {
> +        error_setg(errp, "receive size is too large");
> +        goto fail;
> +    }
> +    ret = qio_channel_read_all(t->cmd_qc, (char *)cmd->out, len, errp);
> +    if (ret != 0)
> +        goto fail;
> +    /* ACK packet */
> +    ret = qio_channel_read_all(t->cmd_qc, (char *)&header, sizeof(header), errp);
> +    if (ret != 0)
> +        goto fail;
> +    if (header != 0) {
> +        error_setg(errp, "incorrect ACK received on command channel 0x%x", len);
> +        goto fail;
> +    }
> +
> +    return;
> +
> + fail:
> +    error_prepend(errp, ERROR_PREFIX);
> +    tpm_util_write_fatal_error_response(cmd->out, cmd->out_len);
> +}
> +
> +static TPMBackend *tpm_mssim_create(QemuOpts *opts)
> +{
> +    TPMBackend *be = TPM_BACKEND(object_new(TYPE_TPM_MSSIM));
> +    TPMmssim *t = TPM_MSSIM(be);
> +    InetSocketAddress cmd_s, ctl_s;
> +    int sock;
> +    const char *host, *port, *ctrl;
> +    Error *errp = NULL;
> +
> +    host = qemu_opt_get(opts, "host");
> +    if (!host)
> +        host = "localhost";
> +    t->opts.host = g_strdup(host);
> +
> +    port = qemu_opt_get(opts, "port");
> +    if (!port)
> +        port = "2321";
> +    t->opts.port = g_strdup(port);
> +
> +    ctrl = qemu_opt_get(opts, "ctrl");
> +    if (!ctrl)
> +        ctrl = "2322";
> +    t->opts.ctrl = g_strdup(ctrl);
> +
> +    cmd_s.host = (char *)host;
> +    cmd_s.port = (char *)port;
> +
> +    ctl_s.host = (char *)host;
> +    ctl_s.port = (char *)ctrl;
> +
> +    sock = inet_connect_saddr(&cmd_s, &errp);
> +    if (sock < 0)
> +        goto fail;
> +    t->cmd_qc = QIO_CHANNEL(qio_channel_socket_new_fd(sock, &errp));
> +    if (errp)
> +        goto fail;
> +    sock = inet_connect_saddr(&ctl_s, &errp);
> +    if (sock < 0)
> +        goto fail_unref_cmd;
> +    t->ctrl_qc = QIO_CHANNEL(qio_channel_socket_new_fd(sock, &errp));
> +    if (errp)
> +        goto fail_unref_cmd;
> +
> +    /* reset the TPM using a power cycle sequence, in case someone
> +     * has previously powered it up */
> +    sock = tpm_send_ctrl(t, TPM_SIGNAL_POWER_OFF, &errp);
> +    if (sock != 0)
> +        goto fail_unref;
> +    sock = tpm_send_ctrl(t, TPM_SIGNAL_POWER_ON, &errp);
> +    if (sock != 0)
> +        goto fail_unref;
> +    sock = tpm_send_ctrl(t, TPM_SIGNAL_NV_ON, &errp);
> +    if (sock != 0)
> +        goto fail_unref;
> +
> +    return be;
> + fail_unref:
> +    object_unref(OBJECT(t->ctrl_qc));
> + fail_unref_cmd:
> +    object_unref(OBJECT(t->cmd_qc));
> + fail:
> +    error_prepend(&errp, ERROR_PREFIX);
> +    error_report_err(errp);
> +    object_unref(OBJECT(be));
> +
> +    return NULL;
> +}
> +
> +static const QemuOptDesc tpm_mssim_cmdline_opts[] = {
> +    TPM_STANDARD_CMDLINE_OPTS,
> +    {
> +        .name = "host",
> +        .type = QEMU_OPT_STRING,
> +        .help = "name or IP address of host to connect to (deault localhost)",
> +    },
> +    {
> +        .name = "port",
> +        .type = QEMU_OPT_STRING,
> +        .help = "port number for standard TPM commands (default 2321)",
> +    },
> +    {
> +        .name = "ctrl",
> +        .type = QEMU_OPT_STRING,
> +        .help = "control port for TPM commands (default 2322)",
> +    },
> +};
> +
> +static void tpm_mssim_class_init(ObjectClass *klass, void *data)
> +{
> +    TPMBackendClass *cl = TPM_BACKEND_CLASS(klass);
> +
> +    cl->type = TPM_TYPE_MSSIM;
> +    cl->opts = tpm_mssim_cmdline_opts;
> +    cl->desc = "TPM mssim emulator backend driver";
> +    cl->create = tpm_mssim_create;
> +    cl->cancel_cmd = tpm_mssim_cancel_cmd;
> +    cl->get_tpm_version = tpm_mssim_get_version;
> +    cl->get_buffer_size = tpm_mssim_get_buffer_size;
> +    cl->get_tpm_options = tpm_mssim_get_opts;
> +    cl->handle_request = tpm_mssim_handle_request;
> +}
> +
> +static const TypeInfo tpm_mssim_info = {
> +    .name = TYPE_TPM_MSSIM,
> +    .parent = TYPE_TPM_BACKEND,
> +    .instance_size = sizeof(TPMmssim),
> +    .class_init = tpm_mssim_class_init,
> +    .instance_init = tpm_mssim_instance_init,
> +    .instance_finalize = tpm_mssim_instance_finalize,
> +};
> +
> +static void tpm_mssim_register(void)
> +{
> +    type_register_static(&tpm_mssim_info);
> +}
> +
> +type_init(tpm_mssim_register)
> diff --git a/backends/tpm/tpm_mssim.h b/backends/tpm/tpm_mssim.h
> new file mode 100644
> index 0000000000..04a270338a
> --- /dev/null
> +++ b/backends/tpm/tpm_mssim.h
> @@ -0,0 +1,43 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * The code below is copied from the Microsoft/TCG Reference implementation
> + *
> + *  https://github.com/Microsoft/ms-tpm-20-ref.git
> + *
> + * In file TPMCmd/Simulator/include/TpmTcpProtocol.h
> + */
> +
> +#define TPM_SIGNAL_POWER_ON         1
> +#define TPM_SIGNAL_POWER_OFF        2
> +#define TPM_SIGNAL_PHYS_PRES_ON     3
> +#define TPM_SIGNAL_PHYS_PRES_OFF    4
> +#define TPM_SIGNAL_HASH_START       5
> +#define TPM_SIGNAL_HASH_DATA        6
> +        // {uint32_t BufferSize, uint8_t[BufferSize] Buffer}
> +#define TPM_SIGNAL_HASH_END         7
> +#define TPM_SEND_COMMAND            8
> +        // {uint8_t Locality, uint32_t InBufferSize, uint8_t[InBufferSize] InBuffer} ->
> +        //     {uint32_t OutBufferSize, uint8_t[OutBufferSize] OutBuffer}
> +
> +#define TPM_SIGNAL_CANCEL_ON        9
> +#define TPM_SIGNAL_CANCEL_OFF       10
> +#define TPM_SIGNAL_NV_ON            11
> +#define TPM_SIGNAL_NV_OFF           12
> +#define TPM_SIGNAL_KEY_CACHE_ON     13
> +#define TPM_SIGNAL_KEY_CACHE_OFF    14
> +
> +#define TPM_REMOTE_HANDSHAKE        15
> +#define TPM_SET_ALTERNATIVE_RESULT  16
> +
> +#define TPM_SIGNAL_RESET            17
> +#define TPM_SIGNAL_RESTART          18
> +
> +#define TPM_SESSION_END             20
> +#define TPM_STOP                    21
> +
> +#define TPM_GET_COMMAND_RESPONSE_SIZES  25
> +
> +#define TPM_ACT_GET_SIGNALED        26
> +
> +#define TPM_TEST_FAILURE_MODE       30
> diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
> index 01b789a79e..f4cd030eab 100644
> --- a/monitor/hmp-cmds.c
> +++ b/monitor/hmp-cmds.c
> @@ -841,6 +841,7 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict)
>       unsigned int c = 0;
>       TPMPassthroughOptions *tpo;
>       TPMEmulatorOptions *teo;
> +    TPMmssimOptions *tmo;
>   
>       info_list = qmp_query_tpm(&err);
>       if (err) {
> @@ -874,6 +875,11 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict)
>               teo = ti->options->u.emulator.data;
>               monitor_printf(mon, ",chardev=%s", teo->chardev);
>               break;
> +        case TPM_TYPE_MSSIM:
> +            tmo = ti->options->u.mssim.data;
> +            monitor_printf(mon, ",host=%s,port=%s,ctl=%s", tmo->host,
> +                           tmo->port, tmo->host);
> +            break;
>           case TPM_TYPE__MAX:
>               break;
>           }
> diff --git a/qapi/tpm.json b/qapi/tpm.json
> index 4e2ea9756a..d92065043e 100644
> --- a/qapi/tpm.json
> +++ b/qapi/tpm.json
> @@ -49,7 +49,7 @@
>   #
>   # Since: 1.5
>   ##
> -{ 'enum': 'TpmType', 'data': [ 'passthrough', 'emulator' ],
> +{ 'enum': 'TpmType', 'data': [ 'passthrough', 'emulator', 'mssim' ],
>     'if': 'CONFIG_TPM' }
>   
>   ##
> @@ -64,7 +64,7 @@
>   # Example:
>   #
>   # -> { "execute": "query-tpm-types" }
> -# <- { "return": [ "passthrough", "emulator" ] }
> +# <- { "return": [ "passthrough", "emulator", "mssim" ] }
>   #
>   ##
>   { 'command': 'query-tpm-types', 'returns': ['TpmType'],
> @@ -99,6 +99,24 @@
>   { 'struct': 'TPMEmulatorOptions', 'data': { 'chardev' : 'str' },
>     'if': 'CONFIG_TPM' }
>   
> +##
> +# @TPMmssimOptions:
> +#
> +# Information for the mssim emulator connection
> +#
> +# @host: host name or IP address to connect to
> +# @port: port for the standard TPM commands
> +# @ctrl: control port for TPM state changes
> +#
> +# Since: 7.2.0
> +##
> +{ 'struct': 'TPMmssimOptions',
> +  'data': {
> +      'host': 'str',
> +      'port': 'str',
> +      'ctrl': 'str' },
> +  'if': 'CONFIG_TPM' }
> +
>   ##
>   # @TPMPassthroughOptionsWrapper:
>   #
> @@ -117,6 +135,15 @@
>     'data': { 'data': 'TPMEmulatorOptions' },
>     'if': 'CONFIG_TPM' }
>   
> +##
> +# @TPMmssimOptionsWrapper:
> +#
> +# Since: 7.2.0
> +##
> +{ 'struct': 'TPMmssimOptionsWrapper',
> +  'data' : { 'data': 'TPMmssimOptions' },
> +  'if': 'CONFIG_TPM' }
> +
>   ##
>   # @TpmTypeOptions:
>   #
> @@ -124,6 +151,7 @@
>   #
>   # @type: - 'passthrough' The configuration options for the TPM passthrough type
>   #        - 'emulator' The configuration options for TPM emulator backend type
> +#        - 'mssim' The configuration options for TPM emulator mssim type
>   #
>   # Since: 1.5
>   ##
> @@ -131,7 +159,8 @@
>     'base': { 'type': 'TpmType' },
>     'discriminator': 'type',
>     'data': { 'passthrough' : 'TPMPassthroughOptionsWrapper',
> -            'emulator': 'TPMEmulatorOptionsWrapper' },
> +            'emulator': 'TPMEmulatorOptionsWrapper',
> +            'mssim': 'TPMmssimOptionsWrapper' },
>     'if': 'CONFIG_TPM' }
>   
>   ##
James Bottomley Dec. 12, 2022, 1:59 p.m. UTC | #2
On Mon, 2022-12-12 at 08:43 -0500, Stefan Berger wrote:
> 
> 
> On 12/10/22 12:10, James Bottomley wrote:
> > The Microsoft Simulator (mssim) is the reference emulation platform
> > for the TCG TPM 2.0 specification.
> > 
> > https://github.com/Microsoft/ms-tpm-20-ref.git
> > 
> > It exports a fairly simple network socket baset protocol on two
> 
> baset -> based.
> 
> > sockets, one for command (default 2321) and one for control
> > (default 2322).  This patch adds a simple backend that can speak
> > the mssim protocol over the network.  It also allows the host, and
> > two ports to be specified on the qemu command line.  The benefits
> > are twofold: firstly it gives us a backend that actually speaks a
> > standard TPM emulation protocol instead of the linux specific TPM
> > driver format of the current emulated TPM backend and secondly,
> > using the microsoft protocol, the end point of the emulator can be
> > anywhere on the network, facilitating the cloud use case where a
> > central TPM ervice can be used over a control network.
> > 
> > The implementation does basic control commands like power off/on,
> > but doesn't implement cancellation or startup.  The former because
> > cancellation is pretty much useless on a fast operating TPM
> > emulator and the latter because this emulator is designed to be
> > used with OVMF which itself does TPM startup and I wanted to
> > validate that.
> 
> How did you implement VM suspend/resume and snapshotting support?

TPM2 doesn't need to.  The mssim follows the reference model which
obeys the TPM2_Shutdown protocol, so the software does a power off with

TPM2_Shutdown(TPM_SU_STATE)

This allows poweroff to preserve the PCR state, provided the startup
does

TPM2_Startup(TPM_SU_STATE).

the edk2 SecurityPackage does this in OVMF on S3 Resume, so using this
backend allows us to check the OVMF startup for correctness.

Now getting QEMU to go through S3 suspend is another issue, but when it
does, the TPM should just work.

James
Stefan Berger Dec. 12, 2022, 2:27 p.m. UTC | #3
On 12/12/22 08:59, James Bottomley wrote:
> On Mon, 2022-12-12 at 08:43 -0500, Stefan Berger wrote:
>>
>>
>> On 12/10/22 12:10, James Bottomley wrote:
>>> The Microsoft Simulator (mssim) is the reference emulation platform
>>> for the TCG TPM 2.0 specification.
>>>
>>> https://github.com/Microsoft/ms-tpm-20-ref.git
>>>
>>> It exports a fairly simple network socket baset protocol on two
>>
>> baset -> based.
>>
>>> sockets, one for command (default 2321) and one for control
>>> (default 2322).  This patch adds a simple backend that can speak
>>> the mssim protocol over the network.  It also allows the host, and
>>> two ports to be specified on the qemu command line.  The benefits
>>> are twofold: firstly it gives us a backend that actually speaks a
>>> standard TPM emulation protocol instead of the linux specific TPM
>>> driver format of the current emulated TPM backend and secondly,
>>> using the microsoft protocol, the end point of the emulator can be
>>> anywhere on the network, facilitating the cloud use case where a
>>> central TPM ervice can be used over a control network.
>>>
>>> The implementation does basic control commands like power off/on,
>>> but doesn't implement cancellation or startup.  The former because
>>> cancellation is pretty much useless on a fast operating TPM
>>> emulator and the latter because this emulator is designed to be
>>> used with OVMF which itself does TPM startup and I wanted to
>>> validate that.
>>
>> How did you implement VM suspend/resume and snapshotting support?
> 
> TPM2 doesn't need to.  The mssim follows the reference model which


You mean TPM2 doesn't need to resume at the point where the VM resumes (I am not talking about ACPI resume but virsh save/restore) after for example a host reboot?
What does this have to do with the mssim reference model and TPM2_Shutdown protocol?

> obeys the TPM2_Shutdown protocol, so the software does a power off with
> 
> TPM2_Shutdown(TPM_SU_STATE)
> 
> This allows poweroff to preserve the PCR state, provided the startup
> does
> 
> TPM2_Startup(TPM_SU_STATE).
> 
> the edk2 SecurityPackage does this in OVMF on S3 Resume, so using this
> backend allows us to check the OVMF startup for correctness.
> 
> Now getting QEMU to go through S3 suspend is another issue, but when it
> does, the TPM should just work.
> 
> James
>
James Bottomley Dec. 12, 2022, 2:32 p.m. UTC | #4
On Mon, 2022-12-12 at 09:27 -0500, Stefan Berger wrote:
> 
> 
> On 12/12/22 08:59, James Bottomley wrote:
> > On Mon, 2022-12-12 at 08:43 -0500, Stefan Berger wrote:
> > > 
> > > 
> > > On 12/10/22 12:10, James Bottomley wrote:
> > > > The Microsoft Simulator (mssim) is the reference emulation
> > > > platform
> > > > for the TCG TPM 2.0 specification.
> > > > 
> > > > https://github.com/Microsoft/ms-tpm-20-ref.git
> > > > 
> > > > It exports a fairly simple network socket baset protocol on two
> > > 
> > > baset -> based.
> > > 
> > > > sockets, one for command (default 2321) and one for control
> > > > (default 2322).  This patch adds a simple backend that can
> > > > speak the mssim protocol over the network.  It also allows the
> > > > host, and two ports to be specified on the qemu command line. 
> > > > The benefits are twofold: firstly it gives us a backend that
> > > > actually speaks a standard TPM emulation protocol instead of
> > > > the linux specific TPM driver format of the current emulated
> > > > TPM backend and secondly, using the microsoft protocol, the end
> > > > point of the emulator can be anywhere on the network,
> > > > facilitating the cloud use case where a central TPM ervice can
> > > > be used over a control network.
> > > > 
> > > > The implementation does basic control commands like power
> > > > off/on, but doesn't implement cancellation or startup.  The
> > > > former because cancellation is pretty much useless on a fast
> > > > operating TPM emulator and the latter because this emulator is
> > > > designed to be used with OVMF which itself does TPM startup and
> > > > I wanted to validate that.
> > > 
> > > How did you implement VM suspend/resume and snapshotting support?
> > 
> > TPM2 doesn't need to.  The mssim follows the reference model which
> 
> 
> You mean TPM2 doesn't need to resume at the point where the VM
> resumes (I am not talking about ACPI resume but virsh save/restore)
> after for example a host reboot?
> What does this have to do with the mssim reference model and
> TPM2_Shutdown protocol?

Running S3 suspend/resume before doing VM save/restore could fix a lot
of issue with passthrough PCI and when QEMU gets around to doing that a
TPM following the standard model should just work.  It's useful to have
a driver supporting this work.

James
Stefan Berger Dec. 12, 2022, 2:44 p.m. UTC | #5
On 12/12/22 09:32, James Bottomley wrote:
> On Mon, 2022-12-12 at 09:27 -0500, Stefan Berger wrote:
>>
>>
>> On 12/12/22 08:59, James Bottomley wrote:
>>> On Mon, 2022-12-12 at 08:43 -0500, Stefan Berger wrote:
>>>>
>>>>
>>>> On 12/10/22 12:10, James Bottomley wrote:
>>>>> The Microsoft Simulator (mssim) is the reference emulation
>>>>> platform
>>>>> for the TCG TPM 2.0 specification.
>>>>>
>>>>> https://github.com/Microsoft/ms-tpm-20-ref.git
>>>>>
>>>>> It exports a fairly simple network socket baset protocol on two
>>>>
>>>> baset -> based.
>>>>
>>>>> sockets, one for command (default 2321) and one for control
>>>>> (default 2322).  This patch adds a simple backend that can
>>>>> speak the mssim protocol over the network.  It also allows the
>>>>> host, and two ports to be specified on the qemu command line.
>>>>> The benefits are twofold: firstly it gives us a backend that
>>>>> actually speaks a standard TPM emulation protocol instead of
>>>>> the linux specific TPM driver format of the current emulated
>>>>> TPM backend and secondly, using the microsoft protocol, the end
>>>>> point of the emulator can be anywhere on the network,
>>>>> facilitating the cloud use case where a central TPM ervice can
>>>>> be used over a control network.
>>>>>
>>>>> The implementation does basic control commands like power
>>>>> off/on, but doesn't implement cancellation or startup.  The
>>>>> former because cancellation is pretty much useless on a fast
>>>>> operating TPM emulator and the latter because this emulator is
>>>>> designed to be used with OVMF which itself does TPM startup and
>>>>> I wanted to validate that.
>>>>
>>>> How did you implement VM suspend/resume and snapshotting support?
>>>
>>> TPM2 doesn't need to.  The mssim follows the reference model which
>>
>>
>> You mean TPM2 doesn't need to resume at the point where the VM
>> resumes (I am not talking about ACPI resume but virsh save/restore)
>> after for example a host reboot?
>> What does this have to do with the mssim reference model and
>> TPM2_Shutdown protocol?
> 
> Running S3 suspend/resume before doing VM save/restore could fix a lot
> of issue with passthrough PCI and when QEMU gets around to doing that a
> TPM following the standard model should just work.  It's useful to have
> a driver supporting this work.
Did you test it with virsh save / restore with the mssim TPM? Does it work? Does it work if you reboot the host in between?

    Stefan

> 
> James
>
James Bottomley Dec. 12, 2022, 2:47 p.m. UTC | #6
On Mon, 2022-12-12 at 09:44 -0500, Stefan Berger wrote:
> 
> 
> On 12/12/22 09:32, James Bottomley wrote:
> > On Mon, 2022-12-12 at 09:27 -0500, Stefan Berger wrote:
> > > 
> > > 
> > > On 12/12/22 08:59, James Bottomley wrote:
> > > > On Mon, 2022-12-12 at 08:43 -0500, Stefan Berger wrote:
> > > > > 
> > > > > 
> > > > > On 12/10/22 12:10, James Bottomley wrote:
> > > > > > The Microsoft Simulator (mssim) is the reference emulation
> > > > > > platform
> > > > > > for the TCG TPM 2.0 specification.
> > > > > > 
> > > > > > https://github.com/Microsoft/ms-tpm-20-ref.git
> > > > > > 
> > > > > > It exports a fairly simple network socket baset protocol on
> > > > > > two
> > > > > 
> > > > > baset -> based.
> > > > > 
> > > > > > sockets, one for command (default 2321) and one for control
> > > > > > (default 2322).  This patch adds a simple backend that can
> > > > > > speak the mssim protocol over the network.  It also allows
> > > > > > the
> > > > > > host, and two ports to be specified on the qemu command
> > > > > > line.
> > > > > > The benefits are twofold: firstly it gives us a backend
> > > > > > that
> > > > > > actually speaks a standard TPM emulation protocol instead
> > > > > > of
> > > > > > the linux specific TPM driver format of the current
> > > > > > emulated
> > > > > > TPM backend and secondly, using the microsoft protocol, the
> > > > > > end
> > > > > > point of the emulator can be anywhere on the network,
> > > > > > facilitating the cloud use case where a central TPM ervice
> > > > > > can
> > > > > > be used over a control network.
> > > > > > 
> > > > > > The implementation does basic control commands like power
> > > > > > off/on, but doesn't implement cancellation or startup.  The
> > > > > > former because cancellation is pretty much useless on a
> > > > > > fast
> > > > > > operating TPM emulator and the latter because this emulator
> > > > > > is
> > > > > > designed to be used with OVMF which itself does TPM startup
> > > > > > and
> > > > > > I wanted to validate that.
> > > > > 
> > > > > How did you implement VM suspend/resume and snapshotting
> > > > > support?
> > > > 
> > > > TPM2 doesn't need to.  The mssim follows the reference model
> > > > which
> > > 
> > > 
> > > You mean TPM2 doesn't need to resume at the point where the VM
> > > resumes (I am not talking about ACPI resume but virsh
> > > save/restore)
> > > after for example a host reboot?
> > > What does this have to do with the mssim reference model and
> > > TPM2_Shutdown protocol?
> > 
> > Running S3 suspend/resume before doing VM save/restore could fix a
> > lot of issue with passthrough PCI and when QEMU gets around to
> > doing that a TPM following the standard model should just work. 
> > It's useful to have a driver supporting this work.
> Did you test it with virsh save / restore with the mssim TPM? Does it
> work? Does it work if you reboot the host in between?

I don't actually use virsh in my harness.  I'm mostly interested in the
running the kernel TPM selftests against the reference model.  But I
anticipate it wouldn't currently work because I don't believe virsh
triggers a S3 event which is why snapshot and migration doesn't always
work with PCI passthrough.

James
Stefan Berger Dec. 12, 2022, 3:20 p.m. UTC | #7
On 12/12/22 09:47, James Bottomley wrote:
> On Mon, 2022-12-12 at 09:44 -0500, Stefan Berger wrote:
>>
>>
>> On 12/12/22 09:32, James Bottomley wrote:
>>> On Mon, 2022-12-12 at 09:27 -0500, Stefan Berger wrote:
>>>>
>>>>
>>>> On 12/12/22 08:59, James Bottomley wrote:
>>>>> On Mon, 2022-12-12 at 08:43 -0500, Stefan Berger wrote:
>>>>>>
>>>>>>
>>>>>> On 12/10/22 12:10, James Bottomley wrote:
>>>>>>> The Microsoft Simulator (mssim) is the reference emulation
>>>>>>> platform
>>>>>>> for the TCG TPM 2.0 specification.
>>>>>>>
>>>>>>> https://github.com/Microsoft/ms-tpm-20-ref.git
>>>>>>>
>>>>>>> It exports a fairly simple network socket baset protocol on
>>>>>>> two
>>>>>>
>>>>>> baset -> based.
>>>>>>
>>>>>>> sockets, one for command (default 2321) and one for control
>>>>>>> (default 2322).  This patch adds a simple backend that can
>>>>>>> speak the mssim protocol over the network.  It also allows
>>>>>>> the
>>>>>>> host, and two ports to be specified on the qemu command
>>>>>>> line.
>>>>>>> The benefits are twofold: firstly it gives us a backend
>>>>>>> that
>>>>>>> actually speaks a standard TPM emulation protocol instead
>>>>>>> of
>>>>>>> the linux specific TPM driver format of the current
>>>>>>> emulated
>>>>>>> TPM backend and secondly, using the microsoft protocol, the
>>>>>>> end
>>>>>>> point of the emulator can be anywhere on the network,
>>>>>>> facilitating the cloud use case where a central TPM ervice
>>>>>>> can
>>>>>>> be used over a control network.
>>>>>>>
>>>>>>> The implementation does basic control commands like power
>>>>>>> off/on, but doesn't implement cancellation or startup.  The
>>>>>>> former because cancellation is pretty much useless on a
>>>>>>> fast
>>>>>>> operating TPM emulator and the latter because this emulator
>>>>>>> is
>>>>>>> designed to be used with OVMF which itself does TPM startup
>>>>>>> and
>>>>>>> I wanted to validate that.
>>>>>>
>>>>>> How did you implement VM suspend/resume and snapshotting
>>>>>> support?
>>>>>
>>>>> TPM2 doesn't need to.  The mssim follows the reference model
>>>>> which
>>>>
>>>>
>>>> You mean TPM2 doesn't need to resume at the point where the VM
>>>> resumes (I am not talking about ACPI resume but virsh
>>>> save/restore)
>>>> after for example a host reboot?
>>>> What does this have to do with the mssim reference model and
>>>> TPM2_Shutdown protocol?
>>>
>>> Running S3 suspend/resume before doing VM save/restore could fix a
>>> lot of issue with passthrough PCI and when QEMU gets around to
>>> doing that a TPM following the standard model should just work.
>>> It's useful to have a driver supporting this work.
>> Did you test it with virsh save / restore with the mssim TPM? Does it
>> work? Does it work if you reboot the host in between?
> 
> I don't actually use virsh in my harness.  I'm mostly interested in the
> running the kernel TPM selftests against the reference model.  But I
> anticipate it wouldn't currently work because I don't believe virsh
> triggers a S3 event which is why snapshot and migration doesn't always
> work with PCI passthrough.

Then I think you should at least add a blocker to your model so that suspend/resume/snapshotting/migration are all disabled because the mssim reference implementation doesn't support permanent & volatile state suspend/resume (and upgrading!) without significant work on it as can be seen in libtpms.

Why would we support another model for the backend that provides no advantages over what is there right now?

   Stefan

> 
> James
> 
> 
> 
>
James Bottomley Dec. 12, 2022, 3:28 p.m. UTC | #8
On Mon, 2022-12-12 at 10:20 -0500, Stefan Berger wrote:
> On 12/12/22 09:47, James Bottomley wrote:
[...]
> > I don't actually use virsh in my harness.  I'm mostly interested in
> > the running the kernel TPM selftests against the reference model. 
> > But I anticipate it wouldn't currently work because I don't believe
> > virsh triggers a S3 event which is why snapshot and migration
> > doesn't always work with PCI passthrough.
> 
> Then I think you should at least add a blocker to your model so that
> suspend/resume/snapshotting/migration are all disabled because the
> mssim reference implementation doesn't support permanent & volatile
> state suspend/resume (and upgrading!) without significant work on it
> as can be seen in libtpms.

Actually, I would think adding support, if that's what people wanted,
would be pretty simple.  Since the network end point is the identifier,
the protocol would be not to power down the TPM on suspend/resume and
simply to send TPM_STOP to close down the sockets gracefully.  Then the
next connection picks up the state where the previous one left off.

> Why would we support another model for the backend that provides no
> advantages over what is there right now?

The advantages were what was stated: ability to connect to the MS
reference model directly and no dependence on the Linux VTPM_PROXY
protocol.

James
Stefan Berger Dec. 12, 2022, 3:46 p.m. UTC | #9
On 12/12/22 10:28, James Bottomley wrote:
> On Mon, 2022-12-12 at 10:20 -0500, Stefan Berger wrote:
>> On 12/12/22 09:47, James Bottomley wrote:
> [...]
>>> I don't actually use virsh in my harness.  I'm mostly interested in
>>> the running the kernel TPM selftests against the reference model.
>>> But I anticipate it wouldn't currently work because I don't believe
>>> virsh triggers a S3 event which is why snapshot and migration
>>> doesn't always work with PCI passthrough.
>>
>> Then I think you should at least add a blocker to your model so that
>> suspend/resume/snapshotting/migration are all disabled because the
>> mssim reference implementation doesn't support permanent & volatile
>> state suspend/resume (and upgrading!) without significant work on it
>> as can be seen in libtpms.
> 
> Actually, I would think adding support, if that's what people wanted,
> would be pretty simple.  Since the network end point is the identifier,
There's VM snapshotting as well where things are not as simple. Host reboot is a bit of a challenge when your TPM 2 emulator doesn't support permanent AND volatile state marshalling and unmarshalling. Upgrading the reference model has also been a challenge in the past where it couldn't read old state anymore when new pieces were added to the state. These were areas where efforts went into libtpms for example. This is not to say that everything is perfect with libtpms and swptm since they have thier own challenges but they have at least resolved some of the issues.

> the protocol would be not to power down the TPM on suspend/resume and
> simply to send TPM_STOP to close down the sockets gracefully.  Then the
> next connection picks up the state where the previous one left off.
> 
>> Why would we support another model for the backend that provides no
>> advantages over what is there right now?
> 
> The advantages were what was stated: ability to connect to the MS
> reference model directly and no dependence on the Linux VTPM_PROXY
> protocol.

We already have a working TPM 2 emulator that does support VM suspend/resume/snapshotting and migration. If you want to become maintainer of your backend model and everything associated with it, please add yourself to the MAINTAINERS list.

> 
> James
>
Daniel P. Berrangé Dec. 12, 2022, 3:47 p.m. UTC | #10
Copy'ing Markus for QAPI design feedback.

On Sat, Dec 10, 2022 at 12:10:18PM -0500, James Bottomley wrote:
> The Microsoft Simulator (mssim) is the reference emulation platform
> for the TCG TPM 2.0 specification.
> 
> https://github.com/Microsoft/ms-tpm-20-ref.git
> 
> It exports a fairly simple network socket baset protocol on two
> sockets, one for command (default 2321) and one for control (default
> 2322).  This patch adds a simple backend that can speak the mssim
> protocol over the network.  It also allows the host, and two ports to
> be specified on the qemu command line.  The benefits are twofold:
> firstly it gives us a backend that actually speaks a standard TPM
> emulation protocol instead of the linux specific TPM driver format of
> the current emulated TPM backend and secondly, using the microsoft
> protocol, the end point of the emulator can be anywhere on the
> network, facilitating the cloud use case where a central TPM service
> can be used over a control network.

What's the story with security for this ?  The patch isn't using
TLS, so talking to any emulator over anything other than localhost
looks insecure, unless I'm missing something.



> diff --git a/backends/tpm/tpm_mssim.c b/backends/tpm/tpm_mssim.c
> new file mode 100644
> index 0000000000..6864b1fbc0
> --- /dev/null
> +++ b/backends/tpm/tpm_mssim.c
> @@ -0,0 +1,266 @@
> +/*
> + * Emulator TPM driver which connects over the mssim protocol
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + *
> + * Copyright (c) 2022

Copyright by whom ?  Presumably this line should have "IBM" present
if we're going to have it at all.

> + * Author: James Bottomley <jejb@linux.ibm.com>
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/error-report.h"
> +#include "qemu/sockets.h"
> +
> +#include "qapi/clone-visitor.h"
> +#include "qapi/qapi-visit-tpm.h"
> +
> +#include "io/channel-socket.h"
> +
> +#include "sysemu/tpm_backend.h"
> +#include "sysemu/tpm_util.h"
> +
> +#include "qom/object.h"
> +
> +#include "tpm_int.h"
> +#include "tpm_mssim.h"
> +

> +static TPMBackend *tpm_mssim_create(QemuOpts *opts)
> +{
> +    TPMBackend *be = TPM_BACKEND(object_new(TYPE_TPM_MSSIM));
> +    TPMmssim *t = TPM_MSSIM(be);
> +    InetSocketAddress cmd_s, ctl_s;
> +    int sock;
> +    const char *host, *port, *ctrl;
> +    Error *errp = NULL;
> +
> +    host = qemu_opt_get(opts, "host");
> +    if (!host)
> +        host = "localhost";
> +    t->opts.host = g_strdup(host);
> +
> +    port = qemu_opt_get(opts, "port");
> +    if (!port)
> +        port = "2321";
> +    t->opts.port = g_strdup(port);
> +
> +    ctrl = qemu_opt_get(opts, "ctrl");
> +    if (!ctrl)
> +        ctrl = "2322";
> +    t->opts.ctrl = g_strdup(ctrl);
> +
> +    cmd_s.host = (char *)host;
> +    cmd_s.port = (char *)port;
> +
> +    ctl_s.host = (char *)host;
> +    ctl_s.port = (char *)ctrl;
> +
> +    sock = inet_connect_saddr(&cmd_s, &errp);
> +    if (sock < 0)
> +        goto fail;
> +    t->cmd_qc = QIO_CHANNEL(qio_channel_socket_new_fd(sock, &errp));
> +    if (errp)
> +        goto fail;
> +    sock = inet_connect_saddr(&ctl_s, &errp);
> +    if (sock < 0)
> +        goto fail_unref_cmd;
> +    t->ctrl_qc = QIO_CHANNEL(qio_channel_socket_new_fd(sock, &errp));
> +    if (errp)
> +        goto fail_unref_cmd;

We don't want to be using inet_connect_saddr, that's a legacy
API. All new code should be using the qio_channel_socket_connect*
family of APIs. This is trivial if the QAPI design uses SocketAddress
structs directly.

> +
> +    /* reset the TPM using a power cycle sequence, in case someone
> +     * has previously powered it up */
> +    sock = tpm_send_ctrl(t, TPM_SIGNAL_POWER_OFF, &errp);
> +    if (sock != 0)
> +        goto fail_unref;
> +    sock = tpm_send_ctrl(t, TPM_SIGNAL_POWER_ON, &errp);
> +    if (sock != 0)
> +        goto fail_unref;
> +    sock = tpm_send_ctrl(t, TPM_SIGNAL_NV_ON, &errp);
> +    if (sock != 0)
> +        goto fail_unref;
> +
> +    return be;
> + fail_unref:
> +    object_unref(OBJECT(t->ctrl_qc));
> + fail_unref_cmd:
> +    object_unref(OBJECT(t->cmd_qc));
> + fail:
> +    error_prepend(&errp, ERROR_PREFIX);
> +    error_report_err(errp);
> +    object_unref(OBJECT(be));
> +
> +    return NULL;
> +}
> +
> +static const QemuOptDesc tpm_mssim_cmdline_opts[] = {
> +    TPM_STANDARD_CMDLINE_OPTS,
> +    {
> +        .name = "host",
> +        .type = QEMU_OPT_STRING,
> +        .help = "name or IP address of host to connect to (deault localhost)",
> +    },
> +    {
> +        .name = "port",
> +        .type = QEMU_OPT_STRING,
> +        .help = "port number for standard TPM commands (default 2321)",
> +    },
> +    {
> +        .name = "ctrl",
> +        .type = QEMU_OPT_STRING,
> +        .help = "control port for TPM commands (default 2322)",
> +    },
> +};
> +
> +static void tpm_mssim_class_init(ObjectClass *klass, void *data)
> +{
> +    TPMBackendClass *cl = TPM_BACKEND_CLASS(klass);
> +
> +    cl->type = TPM_TYPE_MSSIM;
> +    cl->opts = tpm_mssim_cmdline_opts;
> +    cl->desc = "TPM mssim emulator backend driver";
> +    cl->create = tpm_mssim_create;
> +    cl->cancel_cmd = tpm_mssim_cancel_cmd;
> +    cl->get_tpm_version = tpm_mssim_get_version;
> +    cl->get_buffer_size = tpm_mssim_get_buffer_size;
> +    cl->get_tpm_options = tpm_mssim_get_opts;
> +    cl->handle_request = tpm_mssim_handle_request;
> +}


>  
> +##
> +# @TPMmssimOptions:
> +#
> +# Information for the mssim emulator connection
> +#
> +# @host: host name or IP address to connect to
> +# @port: port for the standard TPM commands
> +# @ctrl: control port for TPM state changes
> +#
> +# Since: 7.2.0
> +##
> +{ 'struct': 'TPMmssimOptions',
> +  'data': {
> +      'host': 'str',
> +      'port': 'str',
> +      'ctrl': 'str' },
> +  'if': 'CONFIG_TPM' }

We don't want to be adding new code using plain host/port combos,
as that misses extra functionality for controlling IPv4 vs IPv6
usage.

The existing 'emulator' backend references a chardev, but I'm
not especially in favour of using the chardev indirection either,
when all we should really need is a SocketAddress

IOW, from a QAPI design POV, IMHO the best practice would be

 { 'struct': 'TPMmssimOptions',
   'data': {
       'command': 'SocketAddress',
       'control': 'SocketAddress' },
   'if': 'CONFIG_TPM' }


The main wrinkle with this is that exprssing nested struct fields
with QemuOpts is a disaster zone, and -tpmdev doesn't yet support
JSON syntax.

IMHO we should just fix the latter problem, as I don't think it
ought to be too hard. Probably a cut+paste / search/replace job
on the chanmge we did for -device in:

  commit 5dacda5167560b3af8eadbce5814f60ba44b467e
  Author: Kevin Wolf <kwolf@redhat.com>
  Date:   Fri Oct 8 15:34:42 2021 +0200

    vl: Enable JSON syntax for -device

This would mean we could use plain -tpmdev for a local instance

   -tpmdev mssim,id=tpm0 \
    -device tpm-crb,tpmdev=tpm0 \

but to use a remote emulator we would use

    -tpmdev "{'backend': 'mssim', 'id': 'tpm0',
              'command': {
	         'type': 'inet',
		 'host': 'remote',
		 'port': '4455'
               },
              'control': {
	         'type': 'inet',
		 'host': 'remote',
		 'port': '4456'
               }}"

(without the whitepace/newlines, which i just used for sake of clarity)

With regards,
Daniel
James Bottomley Dec. 12, 2022, 4:38 p.m. UTC | #11
On Mon, 2022-12-12 at 15:47 +0000, Daniel P. Berrangé wrote:
> Copy'ing Markus for QAPI design feedback.
> 
> On Sat, Dec 10, 2022 at 12:10:18PM -0500, James Bottomley wrote:
> > The Microsoft Simulator (mssim) is the reference emulation platform
> > for the TCG TPM 2.0 specification.
> > 
> > https://github.com/Microsoft/ms-tpm-20-ref.git
> > 
> > It exports a fairly simple network socket baset protocol on two
> > sockets, one for command (default 2321) and one for control
> > (default 2322).  This patch adds a simple backend that can speak
> > the mssim protocol over the network.  It also allows the host, and
> > two ports to be specified on the qemu command line.  The benefits
> > are twofold: firstly it gives us a backend that actually speaks a
> > standard TPM emulation protocol instead of the linux specific TPM
> > driver format of the current emulated TPM backend and secondly,
> > using the microsoft protocol, the end point of the emulator can be
> > anywhere on the network, facilitating the cloud use case where a
> > central TPM service can be used over a control network.
> 
> What's the story with security for this ?  The patch isn't using
> TLS, so talking to any emulator over anything other than localhost
> looks insecure, unless I'm missing something.

Pretty much every TPM application fears interposers and should thus be
using the TPM transport security anyway. *If* this is the case, then
the transport is secure.  Note that this currently isn't the case for
the kernel use of the TPM, but I'm trying to fix that.  The standard
mssim server is too simplistic to do transport layer security, but like
everything that does this (or rather doesn't do this), you can front it
with stunnel4.

> > diff --git a/backends/tpm/tpm_mssim.c b/backends/tpm/tpm_mssim.c
> > new file mode 100644
> > index 0000000000..6864b1fbc0
> > --- /dev/null
> > +++ b/backends/tpm/tpm_mssim.c
> > @@ -0,0 +1,266 @@
> > +/*
> > + * Emulator TPM driver which connects over the mssim protocol
> > + * SPDX-License-Identifier: GPL-2.0-or-later
> > + *
> > + * Copyright (c) 2022
> 
> Copyright by whom ?  Presumably this line should have "IBM" present
> if we're going to have it at all.

It can either be me or IBM, we're joint owners, that's why I thought
just author.

> > + * Author: James Bottomley <jejb@linux.ibm.com>
> > + */
> > +
> > +#include "qemu/osdep.h"
> > +#include "qemu/error-report.h"
> > +#include "qemu/sockets.h"
> > +
> > +#include "qapi/clone-visitor.h"
> > +#include "qapi/qapi-visit-tpm.h"
> > +
> > +#include "io/channel-socket.h"
> > +
> > +#include "sysemu/tpm_backend.h"
> > +#include "sysemu/tpm_util.h"
> > +
> > +#include "qom/object.h"
> > +
> > +#include "tpm_int.h"
> > +#include "tpm_mssim.h"
> > +
> 
> > +static TPMBackend *tpm_mssim_create(QemuOpts *opts)
> > +{
> > +    TPMBackend *be = TPM_BACKEND(object_new(TYPE_TPM_MSSIM));
> > +    TPMmssim *t = TPM_MSSIM(be);
> > +    InetSocketAddress cmd_s, ctl_s;
> > +    int sock;
> > +    const char *host, *port, *ctrl;
> > +    Error *errp = NULL;
> > +
> > +    host = qemu_opt_get(opts, "host");
> > +    if (!host)
> > +        host = "localhost";
> > +    t->opts.host = g_strdup(host);
> > +
> > +    port = qemu_opt_get(opts, "port");
> > +    if (!port)
> > +        port = "2321";
> > +    t->opts.port = g_strdup(port);
> > +
> > +    ctrl = qemu_opt_get(opts, "ctrl");
> > +    if (!ctrl)
> > +        ctrl = "2322";
> > +    t->opts.ctrl = g_strdup(ctrl);
> > +
> > +    cmd_s.host = (char *)host;
> > +    cmd_s.port = (char *)port;
> > +
> > +    ctl_s.host = (char *)host;
> > +    ctl_s.port = (char *)ctrl;
> > +
> > +    sock = inet_connect_saddr(&cmd_s, &errp);
> > +    if (sock < 0)
> > +        goto fail;
> > +    t->cmd_qc = QIO_CHANNEL(qio_channel_socket_new_fd(sock,
> > &errp));
> > +    if (errp)
> > +        goto fail;
> > +    sock = inet_connect_saddr(&ctl_s, &errp);
> > +    if (sock < 0)
> > +        goto fail_unref_cmd;
> > +    t->ctrl_qc = QIO_CHANNEL(qio_channel_socket_new_fd(sock,
> > &errp));
> > +    if (errp)
> > +        goto fail_unref_cmd;
> 
> We don't want to be using inet_connect_saddr, that's a legacy
> API. All new code should be using the qio_channel_socket_connect*
> family of APIs. This is trivial if the QAPI design uses SocketAddress
> structs directly.

Heh, well I just copied this from the ssh block backend ...

I can easily find something more modern to update it.

[...]
> >  
> > +##
> > +# @TPMmssimOptions:
> > +#
> > +# Information for the mssim emulator connection
> > +#
> > +# @host: host name or IP address to connect to
> > +# @port: port for the standard TPM commands
> > +# @ctrl: control port for TPM state changes
> > +#
> > +# Since: 7.2.0
> > +##
> > +{ 'struct': 'TPMmssimOptions',
> > +  'data': {
> > +      'host': 'str',
> > +      'port': 'str',
> > +      'ctrl': 'str' },
> > +  'if': 'CONFIG_TPM' }
> 
> We don't want to be adding new code using plain host/port combos,
> as that misses extra functionality for controlling IPv4 vs IPv6
> usage.
> 
> The existing 'emulator' backend references a chardev, but I'm
> not especially in favour of using the chardev indirection either,
> when all we should really need is a SocketAddress

Unfortunately chardev isn't a socket, it really is a character device
that fronts to the vtpm kernel proxy, so even if I convert mssim usage
to socket, you'll still have to keep chardev for the emulator backend.

> 
> IOW, from a QAPI design POV, IMHO the best practice would be
> 
>  { 'struct': 'TPMmssimOptions',
>    'data': {
>        'command': 'SocketAddress',
>        'control': 'SocketAddress' },
>    'if': 'CONFIG_TPM' }
> 
> 
> The main wrinkle with this is that exprssing nested struct fields
> with QemuOpts is a disaster zone, and -tpmdev doesn't yet support
> JSON syntax.
> 
> IMHO we should just fix the latter problem, as I don't think it
> ought to be too hard. Probably a cut+paste / search/replace job
> on the chanmge we did for -device in:
> 
>   commit 5dacda5167560b3af8eadbce5814f60ba44b467e
>   Author: Kevin Wolf <kwolf@redhat.com>
>   Date:   Fri Oct 8 15:34:42 2021 +0200
> 
>     vl: Enable JSON syntax for -device
> 
> This would mean we could use plain -tpmdev for a local instance
> 
>    -tpmdev mssim,id=tpm0 \
>     -device tpm-crb,tpmdev=tpm0 \
> 
> but to use a remote emulator we would use
> 
>     -tpmdev "{'backend': 'mssim', 'id': 'tpm0',
>               'command': {
>                  'type': 'inet',
>                  'host': 'remote',
>                  'port': '4455'
>                },
>               'control': {
>                  'type': 'inet',
>                  'host': 'remote',
>                  'port': '4456'
>                }}"
> 
> (without the whitepace/newlines, which i just used for sake of
> clarity)


OK, I'll look into doing this.

Regards,

James
Stefan Berger Dec. 12, 2022, 4:59 p.m. UTC | #12
On 12/12/22 11:38, James Bottomley wrote:
> On Mon, 2022-12-12 at 15:47 +0000, Daniel P. Berrangé wrote:
>> Copy'ing Markus for QAPI design feedback.
>>
>> On Sat, Dec 10, 2022 at 12:10:18PM -0500, James Bottomley wrote:
>>> The Microsoft Simulator (mssim) is the reference emulation platform
>>> for the TCG TPM 2.0 specification.
>>>
>>> https://github.com/Microsoft/ms-tpm-20-ref.git
>>>
>>> It exports a fairly simple network socket baset protocol on two
>>> sockets, one for command (default 2321) and one for control
>>> (default 2322).  This patch adds a simple backend that can speak
>>> the mssim protocol over the network.  It also allows the host, and
>>> two ports to be specified on the qemu command line.  The benefits
>>> are twofold: firstly it gives us a backend that actually speaks a
>>> standard TPM emulation protocol instead of the linux specific TPM
>>> driver format of the current emulated TPM backend and secondly,
>>> using the microsoft protocol, the end point of the emulator can be
>>> anywhere on the network, facilitating the cloud use case where a
>>> central TPM service can be used over a control network.
>>
>> What's the story with security for this ?  The patch isn't using
>> TLS, so talking to any emulator over anything other than localhost
>> looks insecure, unless I'm missing something.
> 
> Pretty much every TPM application fears interposers and should thus be
> using the TPM transport security anyway. *If* this is the case, then
> the transport is secure.  Note that this currently isn't the case for

What about all the older kernels that are out there?

> the kernel use of the TPM, but I'm trying to fix that.  The standard
> mssim server is too simplistic to do transport layer security, but like
> everything that does this (or rather doesn't do this), you can front it
> with stunnel4.

And who or what is going to set this up?

    Stefan
James Bottomley Dec. 12, 2022, 6:48 p.m. UTC | #13
On Mon, 2022-12-12 at 11:59 -0500, Stefan Berger wrote:
> 
> 
> On 12/12/22 11:38, James Bottomley wrote:
> > On Mon, 2022-12-12 at 15:47 +0000, Daniel P. Berrangé wrote:
> > > Copy'ing Markus for QAPI design feedback.
> > > 
> > > On Sat, Dec 10, 2022 at 12:10:18PM -0500, James Bottomley wrote:
> > > > The Microsoft Simulator (mssim) is the reference emulation
> > > > platform for the TCG TPM 2.0 specification.
> > > > 
> > > > https://github.com/Microsoft/ms-tpm-20-ref.git
> > > > 
> > > > It exports a fairly simple network socket baset protocol on two
> > > > sockets, one for command (default 2321) and one for control
> > > > (default 2322).  This patch adds a simple backend that can
> > > > speak the mssim protocol over the network.  It also allows the
> > > > host, and two ports to be specified on the qemu command line. 
> > > > The benefits are twofold: firstly it gives us a backend that
> > > > actually speaks a standard TPM emulation protocol instead of
> > > > the linux specific TPM driver format of the current emulated
> > > > TPM backend and secondly, using the microsoft protocol, the end
> > > > point of the emulator can be anywhere on the network,
> > > > facilitating the cloud use case where a central TPM service can
> > > > be used over a control network.
> > > 
> > > What's the story with security for this ?  The patch isn't using
> > > TLS, so talking to any emulator over anything other than
> > > localhost looks insecure, unless I'm missing something.
> > 
> > Pretty much every TPM application fears interposers and should thus
> > be using the TPM transport security anyway. *If* this is the case,
> > then the transport is secure.  Note that this currently isn't the
> > case for
> 
> What about all the older kernels that are out there?

No current kernel uses transport security.  In the event the patch
eventually gets upstream, the kernel be secure against interposer
attacks going forwards.  I would imagine there might be pressure to
backport the patch given the current level of worry about interposers.

> > the kernel use of the TPM, but I'm trying to fix that.  The
> > standard mssim server is too simplistic to do transport layer
> > security, but like everything that does this (or rather doesn't do
> > this), you can front it with stunnel4.
> 
> And who or what is going to set this up?

I'm not sure I understand the question.  Stunnel4 is mostly used to
convert unencrypted proxies like imap on 143 or smtp on 25 to the
secure version.  Most people who run servers are fairly familiar with
using it.  It's what IBM used for encrypted migration initially.  You
can run stunnel on both ends, or the qemu side could be built in using
the qemu tls-creds way of doing things but anything running the
standard MS server would have to front it with stunnel still.

James
Stefan Berger Dec. 12, 2022, 6:58 p.m. UTC | #14
On 12/12/22 13:48, James Bottomley wrote:
> On Mon, 2022-12-12 at 11:59 -0500, Stefan Berger wrote:
>>
>>
>> On 12/12/22 11:38, James Bottomley wrote:
>>> On Mon, 2022-12-12 at 15:47 +0000, Daniel P. Berrangé wrote:
>>>> Copy'ing Markus for QAPI design feedback.
>>>>
>>>> On Sat, Dec 10, 2022 at 12:10:18PM -0500, James Bottomley wrote:
>>>>> The Microsoft Simulator (mssim) is the reference emulation
>>>>> platform for the TCG TPM 2.0 specification.
>>>>>
>>>>> https://github.com/Microsoft/ms-tpm-20-ref.git
>>>>>
>>>>> It exports a fairly simple network socket baset protocol on two
>>>>> sockets, one for command (default 2321) and one for control
>>>>> (default 2322).  This patch adds a simple backend that can
>>>>> speak the mssim protocol over the network.  It also allows the
>>>>> host, and two ports to be specified on the qemu command line.
>>>>> The benefits are twofold: firstly it gives us a backend that
>>>>> actually speaks a standard TPM emulation protocol instead of
>>>>> the linux specific TPM driver format of the current emulated
>>>>> TPM backend and secondly, using the microsoft protocol, the end
>>>>> point of the emulator can be anywhere on the network,
>>>>> facilitating the cloud use case where a central TPM service can
>>>>> be used over a control network.
>>>>
>>>> What's the story with security for this ?  The patch isn't using
>>>> TLS, so talking to any emulator over anything other than
>>>> localhost looks insecure, unless I'm missing something.
>>>
>>> Pretty much every TPM application fears interposers and should thus
>>> be using the TPM transport security anyway. *If* this is the case,
>>> then the transport is secure.  Note that this currently isn't the
>>> case for
>>
>> What about all the older kernels that are out there?
> 
> No current kernel uses transport security.  In the event the patch
> eventually gets upstream, the kernel be secure against interposer
> attacks going forwards.  I would imagine there might be pressure to
> backport the patch given the current level of worry about interposers.
> 
>>> the kernel use of the TPM, but I'm trying to fix that.  The
>>> standard mssim server is too simplistic to do transport layer
>>> security, but like everything that does this (or rather doesn't do
>>> this), you can front it with stunnel4.
>>
>> And who or what is going to set this up?
> 
> I'm not sure I understand the question.  Stunnel4 is mostly used to
> convert unencrypted proxies like imap on 143 or smtp on 25 to the
> secure version.  Most people who run servers are fairly familiar with
> using it.  It's what IBM used for encrypted migration initially.  You
> can run stunnel on both ends, or the qemu side could be built in using
> the qemu tls-creds way of doing things but anything running the
> standard MS server would have to front it with stunnel still.


So it's up to libvirt to setup stunnel to support a completely different setup than what it has for swtpm already?

    Stefan

> 
> James
>
James Bottomley Dec. 12, 2022, 7:12 p.m. UTC | #15
On Mon, 2022-12-12 at 13:58 -0500, Stefan Berger wrote:
> On 12/12/22 13:48, James Bottomley wrote:
> > On Mon, 2022-12-12 at 11:59 -0500, Stefan Berger wrote:
> > > On 12/12/22 11:38, James Bottomley wrote:
[...]
> > > > the kernel use of the TPM, but I'm trying to fix that.  The
> > > > standard mssim server is too simplistic to do transport layer
> > > > security, but like everything that does this (or rather doesn't
> > > > do this), you can front it with stunnel4.
> > > 
> > > And who or what is going to set this up?
> > 
> > I'm not sure I understand the question.  Stunnel4 is mostly used to
> > convert unencrypted proxies like imap on 143 or smtp on 25 to the
> > secure version.  Most people who run servers are fairly familiar
> > with using it.  It's what IBM used for encrypted migration
> > initially.  You can run stunnel on both ends, or the qemu side
> > could be built in using the qemu tls-creds way of doing things but
> > anything running the standard MS server would have to front it with
> > stunnel still.
> 
> So it's up to libvirt to setup stunnel to support a completely
> different setup than what it has for swtpm already?

I don't think so, no.  Libvirt doesn't usually help with server setup
(witness the complexity of setting up a server side vtpm proxy) so in
the case tls-creds were built in, it would just work if the object is
specified.  The complexity is all on the server side to front it with
stunnel.

James
Stefan Berger Dec. 12, 2022, 7:32 p.m. UTC | #16
On 12/12/22 14:12, James Bottomley wrote:
> On Mon, 2022-12-12 at 13:58 -0500, Stefan Berger wrote:
>> On 12/12/22 13:48, James Bottomley wrote:
>>> On Mon, 2022-12-12 at 11:59 -0500, Stefan Berger wrote:
>>>> On 12/12/22 11:38, James Bottomley wrote:
> [...]
>>>>> the kernel use of the TPM, but I'm trying to fix that.  The
>>>>> standard mssim server is too simplistic to do transport layer
>>>>> security, but like everything that does this (or rather doesn't
>>>>> do this), you can front it with stunnel4.
>>>>
>>>> And who or what is going to set this up?
>>>
>>> I'm not sure I understand the question.  Stunnel4 is mostly used to
>>> convert unencrypted proxies like imap on 143 or smtp on 25 to the
>>> secure version.  Most people who run servers are fairly familiar
>>> with using it.  It's what IBM used for encrypted migration
>>> initially.  You can run stunnel on both ends, or the qemu side
>>> could be built in using the qemu tls-creds way of doing things but
>>> anything running the standard MS server would have to front it with
>>> stunnel still.
>>
>> So it's up to libvirt to setup stunnel to support a completely
>> different setup than what it has for swtpm already?
> 
> I don't think so, no.  Libvirt doesn't usually help with server setup
> (witness the complexity of setting up a server side vtpm proxy) so in
> the case tls-creds were built in, it would just work if the object is

I see, so you are extending the TPM emulator with TLS on the client side so you don't need another tool to setup a TLS connection from the QEMU/client side.

Is the server side across the network or on the same host? Either way, what is the latency that this introduces because I would expect that this slows down IMA since the PCR extensions & TPM 2 response now go back and forth across the network?

     Stefan

> specified.  The complexity is all on the server side to front it with
> stunnel.
>
> James
>
Stefan Berger Dec. 12, 2022, 8:24 p.m. UTC | #17
On 12/12/22 14:32, Stefan Berger wrote:
> 
> 
> On 12/12/22 14:12, James Bottomley wrote:
>> On Mon, 2022-12-12 at 13:58 -0500, Stefan Berger wrote:
>>> On 12/12/22 13:48, James Bottomley wrote:
>>>> On Mon, 2022-12-12 at 11:59 -0500, Stefan Berger wrote:
>>>>> On 12/12/22 11:38, James Bottomley wrote:
>> [...]
>>>>>> the kernel use of the TPM, but I'm trying to fix that.  The
>>>>>> standard mssim server is too simplistic to do transport layer
>>>>>> security, but like everything that does this (or rather doesn't
>>>>>> do this), you can front it with stunnel4.
>>>>>
>>>>> And who or what is going to set this up?
>>>>
>>>> I'm not sure I understand the question.  Stunnel4 is mostly used to
>>>> convert unencrypted proxies like imap on 143 or smtp on 25 to the
>>>> secure version.  Most people who run servers are fairly familiar
>>>> with using it.  It's what IBM used for encrypted migration
>>>> initially.  You can run stunnel on both ends, or the qemu side
>>>> could be built in using the qemu tls-creds way of doing things but
>>>> anything running the standard MS server would have to front it with
>>>> stunnel still.
>>>
>>> So it's up to libvirt to setup stunnel to support a completely
>>> different setup than what it has for swtpm already?
>>
>> I don't think so, no.  Libvirt doesn't usually help with server setup
>> (witness the complexity of setting up a server side vtpm proxy) so in
>> the case tls-creds were built in, it would just work if the object is
> 
> I see, so you are extending the TPM emulator with TLS on the client side so you don't need another tool to setup a TLS connection from the QEMU/client side.

s/TPM emulator/TPM backend/

> 
> Is the server side across the network or on the same host? Either way, what is the latency that this introduces because I would expect that this slows down IMA since the PCR extensions & TPM 2 response now go back and forth across the network?
> 
>      Stefan
> 
>> specified.  The complexity is all on the server side to front it with
>> stunnel.
>>
>> James
>>
>
James Bottomley Dec. 12, 2022, 9:36 p.m. UTC | #18
On Mon, 2022-12-12 at 14:32 -0500, Stefan Berger wrote:
> 
> 
> On 12/12/22 14:12, James Bottomley wrote:
> > On Mon, 2022-12-12 at 13:58 -0500, Stefan Berger wrote:
> > > On 12/12/22 13:48, James Bottomley wrote:
> > > > On Mon, 2022-12-12 at 11:59 -0500, Stefan Berger wrote:
> > > > > On 12/12/22 11:38, James Bottomley wrote:
> > [...]
> > > > > > the kernel use of the TPM, but I'm trying to fix that.  The
> > > > > > standard mssim server is too simplistic to do transport
> > > > > > layer
> > > > > > security, but like everything that does this (or rather
> > > > > > doesn't
> > > > > > do this), you can front it with stunnel4.
> > > > > 
> > > > > And who or what is going to set this up?
> > > > 
> > > > I'm not sure I understand the question.  Stunnel4 is mostly
> > > > used to
> > > > convert unencrypted proxies like imap on 143 or smtp on 25 to
> > > > the
> > > > secure version.  Most people who run servers are fairly
> > > > familiar
> > > > with using it.  It's what IBM used for encrypted migration
> > > > initially.  You can run stunnel on both ends, or the qemu side
> > > > could be built in using the qemu tls-creds way of doing things
> > > > but
> > > > anything running the standard MS server would have to front it
> > > > with
> > > > stunnel still.
> > > 
> > > So it's up to libvirt to setup stunnel to support a completely
> > > different setup than what it has for swtpm already?
> > 
> > I don't think so, no.  Libvirt doesn't usually help with server
> > setup (witness the complexity of setting up a server side vtpm
> > proxy) so in the case tls-creds were built in, it would just work
> > if the object is
> 
> I see, so you are extending the TPM emulator with TLS on the client
> side so you don't need another tool to setup a TLS connection from
> the QEMU/client side.

I didn't say I would do this, just that it's an easy possibility with
the current qemu framework.  I actually need to fiddle with the TPM
externally to do some of my testing (like platform reset injection) so
I won't use TLS anyway.

> Is the server side across the network or on the same host?

It can be either.

>  Either way, what is the latency that this introduces because I would
> expect that this slows down IMA since the PCR extensions & TPM 2
> response now go back and forth across the network?

Most data centre protocols are now encrypted and networked (NVMeoF
would probably be the poster child) with no real ill effects.  In terms
of a TPM, the competition is an underpowered discrete chip over a slow
serial bus, so I think we'll actually improve the latency not diminish
it.

James
Stefan Berger Dec. 12, 2022, 10:02 p.m. UTC | #19
On 12/12/22 16:36, James Bottomley wrote:
> On Mon, 2022-12-12 at 14:32 -0500, Stefan Berger wrote:
>>
>>
>> On 12/12/22 14:12, James Bottomley wrote:
>>> On Mon, 2022-12-12 at 13:58 -0500, Stefan Berger wrote:
>>>> On 12/12/22 13:48, James Bottomley wrote:
>>>>> On Mon, 2022-12-12 at 11:59 -0500, Stefan Berger wrote:
>>>>>> On 12/12/22 11:38, James Bottomley wrote:
>>> [...]
>>>>>>> the kernel use of the TPM, but I'm trying to fix that.  The
>>>>>>> standard mssim server is too simplistic to do transport
>>>>>>> layer
>>>>>>> security, but like everything that does this (or rather
>>>>>>> doesn't
>>>>>>> do this), you can front it with stunnel4.
>>>>>>
>>>>>> And who or what is going to set this up?
>>>>>
>>>>> I'm not sure I understand the question.  Stunnel4 is mostly
>>>>> used to
>>>>> convert unencrypted proxies like imap on 143 or smtp on 25 to
>>>>> the
>>>>> secure version.  Most people who run servers are fairly
>>>>> familiar
>>>>> with using it.  It's what IBM used for encrypted migration
>>>>> initially.  You can run stunnel on both ends, or the qemu side
>>>>> could be built in using the qemu tls-creds way of doing things
>>>>> but
>>>>> anything running the standard MS server would have to front it
>>>>> with
>>>>> stunnel still.
>>>>
>>>> So it's up to libvirt to setup stunnel to support a completely
>>>> different setup than what it has for swtpm already?
>>>
>>> I don't think so, no.  Libvirt doesn't usually help with server
>>> setup (witness the complexity of setting up a server side vtpm
>>> proxy) so in the case tls-creds were built in, it would just work
>>> if the object is
>>
>> I see, so you are extending the TPM emulator with TLS on the client
>> side so you don't need another tool to setup a TLS connection from
>> the QEMU/client side.
> 
> I didn't say I would do this, just that it's an easy possibility with
> the current qemu framework.  I actually need to fiddle with the TPM
> externally to do some of my testing (like platform reset injection) so
> I won't use TLS anyway.
> 
>> Is the server side across the network or on the same host?
> 
> It can be either.

For the remote TPM you'll need some sort of management stack (who is building this?) that does the port assignments (allocations and freeing, starting of TPM instances etc) for the possibly many TPMs you would run on a remote machine and then create the libvirt XML or QEMU command line with the port assignments. I am not sure I see the advantage of this versus what we have at the moment with a single management stack . Also, if you did this you'd have a single point of failure for many VMs whose TPM is presumably running on some dedicated machine(s).

> 
>>   Either way, what is the latency that this introduces because I would
>> expect that this slows down IMA since the PCR extensions & TPM 2
>> response now go back and forth across the network?
> 
> Most data centre protocols are now encrypted and networked (NVMeoF
> would probably be the poster child) with no real ill effects.  In terms
> of a TPM, the competition is an underpowered discrete chip over a slow
> serial bus, so I think we'll actually improve the latency not diminish
> it.

Compared to QEMU and swtpm talking over a local socket you probably have a decent amount of slow-down if this is over the network.
I still fail to see the advantage over what we have at the moment. Also I don't see what advantage the mssim protocol brings over what swtpm provides. If you are willing to do a 'dnf -y install swtpm_setup' and start the VM via libvirt it really doesn't matter what protocol the TPM is running underneath since it's all transparent.

    Stefan

> 
> James
>
James Bottomley Dec. 12, 2022, 10:06 p.m. UTC | #20
On Mon, 2022-12-12 at 15:47 +0000, Daniel P. Berrangé wrote:
> Copy'ing Markus for QAPI design feedback.
> 
> On Sat, Dec 10, 2022 at 12:10:18PM -0500, James Bottomley wrote:
[...]
> > +##
> > +# @TPMmssimOptions:
> > +#
> > +# Information for the mssim emulator connection
> > +#
> > +# @host: host name or IP address to connect to
> > +# @port: port for the standard TPM commands
> > +# @ctrl: control port for TPM state changes
> > +#
> > +# Since: 7.2.0
> > +##
> > +{ 'struct': 'TPMmssimOptions',
> > +  'data': {
> > +      'host': 'str',
> > +      'port': 'str',
> > +      'ctrl': 'str' },
> > +  'if': 'CONFIG_TPM' }
> 
> We don't want to be adding new code using plain host/port combos,
> as that misses extra functionality for controlling IPv4 vs IPv6
> usage.
> 
> The existing 'emulator' backend references a chardev, but I'm
> not especially in favour of using the chardev indirection either,
> when all we should really need is a SocketAddress
> 
> IOW, from a QAPI design POV, IMHO the best practice would be
> 
>  { 'struct': 'TPMmssimOptions',
>    'data': {
>        'command': 'SocketAddress',
>        'control': 'SocketAddress' },
>    'if': 'CONFIG_TPM' }
> 
> 
> The main wrinkle with this is that exprssing nested struct fields
> with QemuOpts is a disaster zone, and -tpmdev doesn't yet support
> JSON syntax.
> 
> IMHO we should just fix the latter problem, as I don't think it
> ought to be too hard. Probably a cut+paste / search/replace job
> on the chanmge we did for -device in:
> 
>   commit 5dacda5167560b3af8eadbce5814f60ba44b467e
>   Author: Kevin Wolf <kwolf@redhat.com>
>   Date:   Fri Oct 8 15:34:42 2021 +0200
> 
>     vl: Enable JSON syntax for -device
> 
> This would mean we could use plain -tpmdev for a local instance
> 
>    -tpmdev mssim,id=tpm0 \
>     -device tpm-crb,tpmdev=tpm0 \
> 
> but to use a remote emulator we would use
> 
>     -tpmdev "{'backend': 'mssim', 'id': 'tpm0',
>               'command': {
>                  'type': 'inet',
>                  'host': 'remote',
>                  'port': '4455'
>                },
>               'control': {
>                  'type': 'inet',
>                  'host': 'remote',
>                  'port': '4456'
>                }}"
> 
> (without the whitepace/newlines, which i just used for sake of
> clarity)

Just on this, might it not be easier for the commandline to do what
gluster does?  just use the '.' as a separator and subqdict extraction,
so you'd specify

-tpmdev mssim,id=tpm0,command.type=inet,command.host=remote,command.port=4455,control.type=inet,control.host=remote,control.port=4456

With the added bonus that X.type could be defaulted to inet and
control.host could follow command.host and so on?

James
James Bottomley Dec. 12, 2022, 10:27 p.m. UTC | #21
On Mon, 2022-12-12 at 17:02 -0500, Stefan Berger wrote:
> 
> 
> On 12/12/22 16:36, James Bottomley wrote:
> > On Mon, 2022-12-12 at 14:32 -0500, Stefan Berger wrote:
[...]
> > >   Either way, what is the latency that this introduces because I
> > > would expect that this slows down IMA since the PCR extensions &
> > > TPM 2 response now go back and forth across the network?
> > 
> > Most data centre protocols are now encrypted and networked (NVMeoF
> > would probably be the poster child) with no real ill effects.  In
> > terms of a TPM, the competition is an underpowered discrete chip
> > over a slow serial bus, so I think we'll actually improve the
> > latency not diminish it.
> 
> Compared to QEMU and swtpm talking over a local socket you probably
> have a decent amount of slow-down if this is over the network.

I can only repeat that doesn't happen with other much more volume and
latency bound networked protocols.

> I still fail to see the advantage over what we have at the moment.
> Also I don't see what advantage the mssim protocol brings over what
> swtpm provides.

I think I've said a couple of times now: The primary advantage is that
it talks to the reference implementation over its native protocol.

>  If you are willing to do a 'dnf -y install swtpm_setup' and start
> the VM via libvirt it really doesn't matter what protocol the TPM is
> running underneath since it's all transparent.

Swtpm currently isn't building for Leap:

https://build.opensuse.org/package/show/security/swtpm

And, as I said, this is primarily for testing, so I need the reference
implementation ... swtpm has started deviating from it.

James
Stefan Berger Dec. 12, 2022, 10:43 p.m. UTC | #22
On 12/12/22 17:27, James Bottomley wrote:
.
> 
> Swtpm currently isn't building for Leap:
> 
> https://build.opensuse.org/package/show/security/swtpm

Someone could have notified me...
Daniel P. Berrangé Dec. 14, 2022, 11:31 a.m. UTC | #23
On Mon, Dec 12, 2022 at 05:06:05PM -0500, James Bottomley wrote:
> On Mon, 2022-12-12 at 15:47 +0000, Daniel P. Berrangé wrote:
> > Copy'ing Markus for QAPI design feedback.
> > 
> > On Sat, Dec 10, 2022 at 12:10:18PM -0500, James Bottomley wrote:
> [...]
> > > +##
> > > +# @TPMmssimOptions:
> > > +#
> > > +# Information for the mssim emulator connection
> > > +#
> > > +# @host: host name or IP address to connect to
> > > +# @port: port for the standard TPM commands
> > > +# @ctrl: control port for TPM state changes
> > > +#
> > > +# Since: 7.2.0
> > > +##
> > > +{ 'struct': 'TPMmssimOptions',
> > > +  'data': {
> > > +      'host': 'str',
> > > +      'port': 'str',
> > > +      'ctrl': 'str' },
> > > +  'if': 'CONFIG_TPM' }
> > 
> > We don't want to be adding new code using plain host/port combos,
> > as that misses extra functionality for controlling IPv4 vs IPv6
> > usage.
> > 
> > The existing 'emulator' backend references a chardev, but I'm
> > not especially in favour of using the chardev indirection either,
> > when all we should really need is a SocketAddress
> > 
> > IOW, from a QAPI design POV, IMHO the best practice would be
> > 
> >  { 'struct': 'TPMmssimOptions',
> >    'data': {
> >        'command': 'SocketAddress',
> >        'control': 'SocketAddress' },
> >    'if': 'CONFIG_TPM' }
> > 
> > 
> > The main wrinkle with this is that exprssing nested struct fields
> > with QemuOpts is a disaster zone, and -tpmdev doesn't yet support
> > JSON syntax.
> > 
> > IMHO we should just fix the latter problem, as I don't think it
> > ought to be too hard. Probably a cut+paste / search/replace job
> > on the chanmge we did for -device in:
> > 
> >   commit 5dacda5167560b3af8eadbce5814f60ba44b467e
> >   Author: Kevin Wolf <kwolf@redhat.com>
> >   Date:   Fri Oct 8 15:34:42 2021 +0200
> > 
> >     vl: Enable JSON syntax for -device
> > 
> > This would mean we could use plain -tpmdev for a local instance
> > 
> >    -tpmdev mssim,id=tpm0 \
> >     -device tpm-crb,tpmdev=tpm0 \
> > 
> > but to use a remote emulator we would use
> > 
> >     -tpmdev "{'backend': 'mssim', 'id': 'tpm0',
> >               'command': {
> >                  'type': 'inet',
> >                  'host': 'remote',
> >                  'port': '4455'
> >                },
> >               'control': {
> >                  'type': 'inet',
> >                  'host': 'remote',
> >                  'port': '4456'
> >                }}"
> > 
> > (without the whitepace/newlines, which i just used for sake of
> > clarity)
> 
> Just on this, might it not be easier for the commandline to do what
> gluster does?  just use the '.' as a separator and subqdict extraction,
> so you'd specify
> 
> -tpmdev mssim,id=tpm0,command.type=inet,command.host=remote,command.port=4455,control.type=inet,control.host=remote,control.port=4456
> 
> With the added bonus that X.type could be defaulted to inet and
> control.host could follow command.host and so on?

These days, we have a policy of not tyring to map nested data onto the
flat QemuOpts. This has been done in several areas and we've ended up
with a mess of ever so slightly different impls each with their own
flaws. This is why our preferred approach these days is to add support
for JSON syntax to enable non-flat config.


With regards,
Daniel
Daniel P. Berrangé Dec. 14, 2022, 11:52 a.m. UTC | #24
On Mon, Dec 12, 2022 at 05:02:43PM -0500, Stefan Berger wrote:
> 
> 
> On 12/12/22 16:36, James Bottomley wrote:
> > On Mon, 2022-12-12 at 14:32 -0500, Stefan Berger wrote:
> > > 
> > > 
> > > On 12/12/22 14:12, James Bottomley wrote:
> > > > On Mon, 2022-12-12 at 13:58 -0500, Stefan Berger wrote:
> > > > > On 12/12/22 13:48, James Bottomley wrote:
> > > > > > On Mon, 2022-12-12 at 11:59 -0500, Stefan Berger wrote:
> > > > > > > On 12/12/22 11:38, James Bottomley wrote:
> > > > [...]
> > > > > > > > the kernel use of the TPM, but I'm trying to fix that.  The
> > > > > > > > standard mssim server is too simplistic to do transport
> > > > > > > > layer
> > > > > > > > security, but like everything that does this (or rather
> > > > > > > > doesn't
> > > > > > > > do this), you can front it with stunnel4.
> > > > > > > 
> > > > > > > And who or what is going to set this up?
> > > > > > 
> > > > > > I'm not sure I understand the question.  Stunnel4 is mostly
> > > > > > used to
> > > > > > convert unencrypted proxies like imap on 143 or smtp on 25 to
> > > > > > the
> > > > > > secure version.  Most people who run servers are fairly
> > > > > > familiar
> > > > > > with using it.  It's what IBM used for encrypted migration
> > > > > > initially.  You can run stunnel on both ends, or the qemu side
> > > > > > could be built in using the qemu tls-creds way of doing things
> > > > > > but
> > > > > > anything running the standard MS server would have to front it
> > > > > > with
> > > > > > stunnel still.
> > > > > 
> > > > > So it's up to libvirt to setup stunnel to support a completely
> > > > > different setup than what it has for swtpm already?
> > > > 
> > > > I don't think so, no.  Libvirt doesn't usually help with server
> > > > setup (witness the complexity of setting up a server side vtpm
> > > > proxy) so in the case tls-creds were built in, it would just work
> > > > if the object is
> > > 
> > > I see, so you are extending the TPM emulator with TLS on the client
> > > side so you don't need another tool to setup a TLS connection from
> > > the QEMU/client side.
> > 
> > I didn't say I would do this, just that it's an easy possibility with
> > the current qemu framework.  I actually need to fiddle with the TPM
> > externally to do some of my testing (like platform reset injection) so
> > I won't use TLS anyway.
> > 
> > > Is the server side across the network or on the same host?
> > 
> > It can be either.
> 
> For the remote TPM you'll need some sort of management stack (who
> is building this?) that does the port assignments (allocations and
> freeing, starting of TPM instances etc) for the possibly many TPMs
> you would run on a remote machine and then create the libvirt XML
> or QEMU command line with the port assignments. I am not sure I
> see the advantage of this versus what we have at the moment with a
> single management stack . Also, if you did this you'd have a single
> point of failure for many VMs whose TPM is presumably running on
> some dedicated machine(s).

IMHO this is largely tangential. Remote access is technically possible,
but local access is likely the common case. It isn't neccessary to
solve the full remote mgmt solution as a pre-condition for this
proposed patch.

All that matters is whether it is valuable to have the mssim backend
in QEMU. I think the benefit is weak when considering a full virt
mgmt stack like OpenStack/KubeVirt, as swtpm basically solves
everything people need to commonly do AFAICT.

None the less, I can understand why it is desirable to have the option
be able to run against the TPM reference implementation, for the sake
of testing behavioural compliance.

It is a shame there isn't a standardized protocol for software TPM
communication, as that'd avoid the need for multiple backends.

With regards,
Daniel
Daniel P. Berrangé Dec. 14, 2022, 11:55 a.m. UTC | #25
On Mon, Dec 12, 2022 at 01:58:29PM -0500, Stefan Berger wrote:
> 
> 
> On 12/12/22 13:48, James Bottomley wrote:
> > On Mon, 2022-12-12 at 11:59 -0500, Stefan Berger wrote:
> > > 
> > > 
> > > On 12/12/22 11:38, James Bottomley wrote:
> > > > On Mon, 2022-12-12 at 15:47 +0000, Daniel P. Berrangé wrote:
> > > > > Copy'ing Markus for QAPI design feedback.
> > > > > 
> > > > > On Sat, Dec 10, 2022 at 12:10:18PM -0500, James Bottomley wrote:
> > > > > > The Microsoft Simulator (mssim) is the reference emulation
> > > > > > platform for the TCG TPM 2.0 specification.
> > > > > > 
> > > > > > https://github.com/Microsoft/ms-tpm-20-ref.git
> > > > > > 
> > > > > > It exports a fairly simple network socket baset protocol on two
> > > > > > sockets, one for command (default 2321) and one for control
> > > > > > (default 2322).  This patch adds a simple backend that can
> > > > > > speak the mssim protocol over the network.  It also allows the
> > > > > > host, and two ports to be specified on the qemu command line.
> > > > > > The benefits are twofold: firstly it gives us a backend that
> > > > > > actually speaks a standard TPM emulation protocol instead of
> > > > > > the linux specific TPM driver format of the current emulated
> > > > > > TPM backend and secondly, using the microsoft protocol, the end
> > > > > > point of the emulator can be anywhere on the network,
> > > > > > facilitating the cloud use case where a central TPM service can
> > > > > > be used over a control network.
> > > > > 
> > > > > What's the story with security for this ?  The patch isn't using
> > > > > TLS, so talking to any emulator over anything other than
> > > > > localhost looks insecure, unless I'm missing something.
> > > > 
> > > > Pretty much every TPM application fears interposers and should thus
> > > > be using the TPM transport security anyway. *If* this is the case,
> > > > then the transport is secure.  Note that this currently isn't the
> > > > case for
> > > 
> > > What about all the older kernels that are out there?
> > 
> > No current kernel uses transport security.  In the event the patch
> > eventually gets upstream, the kernel be secure against interposer
> > attacks going forwards.  I would imagine there might be pressure to
> > backport the patch given the current level of worry about interposers.
> > 
> > > > the kernel use of the TPM, but I'm trying to fix that.  The
> > > > standard mssim server is too simplistic to do transport layer
> > > > security, but like everything that does this (or rather doesn't do
> > > > this), you can front it with stunnel4.
> > > 
> > > And who or what is going to set this up?
> > 
> > I'm not sure I understand the question.  Stunnel4 is mostly used to
> > convert unencrypted proxies like imap on 143 or smtp on 25 to the
> > secure version.  Most people who run servers are fairly familiar with
> > using it.  It's what IBM used for encrypted migration initially.  You
> > can run stunnel on both ends, or the qemu side could be built in using
> > the qemu tls-creds way of doing things but anything running the
> > standard MS server would have to front it with stunnel still.
> 
> 
> So it's up to libvirt to setup stunnel to support a completely
> different setup than what it has for swtpm already?

Well technically libvirt doesn't have todo anything. We are free
to decide to only support locally hosted mssim deployments, and
declare that off node access is unsupported and warn it is
potentially insecure .

With regards,
Daniel
James Bottomley Dec. 14, 2022, 12:43 p.m. UTC | #26
On Wed, 2022-12-14 at 11:52 +0000, Daniel P. Berrangé wrote:
> It is a shame there isn't a standardized protocol for software TPM
> communication, as that'd avoid the need for multiple backends.

Technically the mssim protocol is the standard, being part of the
reference implementation, but practically it's terrible:  Using two
ports per vTPM is hardly scalable in a cloud situation and, as you say,
it has no security.  Ideally someone with TCG connections would try to
standardize a more scalable network server protocol, something nicely
rest based that identified the vTPM by say its EK name.

James
James Bottomley Dec. 14, 2022, 12:47 p.m. UTC | #27
On Wed, 2022-12-14 at 11:31 +0000, Daniel P. Berrangé wrote:
> On Mon, Dec 12, 2022 at 05:06:05PM -0500, James Bottomley wrote:
> > On Mon, 2022-12-12 at 15:47 +0000, Daniel P. Berrangé wrote:
> > > Copy'ing Markus for QAPI design feedback.
> > > 
> > > On Sat, Dec 10, 2022 at 12:10:18PM -0500, James Bottomley wrote:
> > [...]
> > > > +##
> > > > +# @TPMmssimOptions:
> > > > +#
> > > > +# Information for the mssim emulator connection
> > > > +#
> > > > +# @host: host name or IP address to connect to
> > > > +# @port: port for the standard TPM commands
> > > > +# @ctrl: control port for TPM state changes
> > > > +#
> > > > +# Since: 7.2.0
> > > > +##
> > > > +{ 'struct': 'TPMmssimOptions',
> > > > +  'data': {
> > > > +      'host': 'str',
> > > > +      'port': 'str',
> > > > +      'ctrl': 'str' },
> > > > +  'if': 'CONFIG_TPM' }
> > > 
> > > We don't want to be adding new code using plain host/port combos,
> > > as that misses extra functionality for controlling IPv4 vs IPv6
> > > usage.
> > > 
> > > The existing 'emulator' backend references a chardev, but I'm
> > > not especially in favour of using the chardev indirection either,
> > > when all we should really need is a SocketAddress
> > > 
> > > IOW, from a QAPI design POV, IMHO the best practice would be
> > > 
> > >  { 'struct': 'TPMmssimOptions',
> > >    'data': {
> > >        'command': 'SocketAddress',
> > >        'control': 'SocketAddress' },
> > >    'if': 'CONFIG_TPM' }
> > > 
> > > 
> > > The main wrinkle with this is that exprssing nested struct fields
> > > with QemuOpts is a disaster zone, and -tpmdev doesn't yet support
> > > JSON syntax.
> > > 
> > > IMHO we should just fix the latter problem, as I don't think it
> > > ought to be too hard. Probably a cut+paste / search/replace job
> > > on the chanmge we did for -device in:
> > > 
> > >   commit 5dacda5167560b3af8eadbce5814f60ba44b467e
> > >   Author: Kevin Wolf <kwolf@redhat.com>
> > >   Date:   Fri Oct 8 15:34:42 2021 +0200
> > > 
> > >     vl: Enable JSON syntax for -device
> > > 
> > > This would mean we could use plain -tpmdev for a local instance
> > > 
> > >    -tpmdev mssim,id=tpm0 \
> > >     -device tpm-crb,tpmdev=tpm0 \
> > > 
> > > but to use a remote emulator we would use
> > > 
> > >     -tpmdev "{'backend': 'mssim', 'id': 'tpm0',
> > >               'command': {
> > >                  'type': 'inet',
> > >                  'host': 'remote',
> > >                  'port': '4455'
> > >                },
> > >               'control': {
> > >                  'type': 'inet',
> > >                  'host': 'remote',
> > >                  'port': '4456'
> > >                }}"
> > > 
> > > (without the whitepace/newlines, which i just used for sake of
> > > clarity)
> > 
> > Just on this, might it not be easier for the commandline to do what
> > gluster does?  just use the '.' as a separator and subqdict
> > extraction, so you'd specify
> > 
> > -tpmdev
> > mssim,id=tpm0,command.type=inet,command.host=remote,command.port=44
> > 55,control.type=inet,control.host=remote,control.port=4456
> > 
> > With the added bonus that X.type could be defaulted to inet and
> > control.host could follow command.host and so on?
> 
> These days, we have a policy of not tyring to map nested data onto
> the flat QemuOpts. This has been done in several areas and we've
> ended up with a mess of ever so slightly different impls each with
> their own flaws. This is why our preferred approach these days is to
> add support for JSON syntax to enable non-flat config.

Well, OK, but I've got to say on behalf of shell script writers
everywhere that using json for command line arguments is a textbook
definition of cruel and unusual punishment.

James
Markus Armbruster Dec. 14, 2022, 2:17 p.m. UTC | #28
James Bottomley <jejb@linux.ibm.com> writes:

> On Wed, 2022-12-14 at 11:31 +0000, Daniel P. Berrangé wrote:

[...]

>> These days, we have a policy of not tyring to map nested data onto
>> the flat QemuOpts. This has been done in several areas and we've
>> ended up with a mess of ever so slightly different impls each with
>> their own flaws. This is why our preferred approach these days is to
>> add support for JSON syntax to enable non-flat config.
>
> Well, OK, but I've got to say on behalf of shell script writers
> everywhere that using json for command line arguments is a textbook
> definition of cruel and unusual punishment.

For new code, use qobject_input_visitor_new_str().  Parses both JSON and
dotted keys.  Example: case QEMU_OPTION_blockdev in qemu_init().  Dotted
keys can fall apart for corner cases.  See util/keyval.c if you're
curious.

Sometimes we bend over backwards for backward compatibility, and do
something like

    if (optarg[0] == '{') {
        QObject *obj = qobject_from_json(optarg, &error_fatal);

        v = qobject_input_visitor_new(obj);
        qobject_unref(obj);
    } else {
        ... old parser ...
    }

This parses both JSON and whatever old crap.  Example:
object_option_parse().

Questions?
Stefan Berger Dec. 15, 2022, 2:42 a.m. UTC | #29
On 12/14/22 07:43, James Bottomley wrote:
> On Wed, 2022-12-14 at 11:52 +0000, Daniel P. Berrangé wrote:
>> It is a shame there isn't a standardized protocol for software TPM
>> communication, as that'd avoid the need for multiple backends.
> 
> Technically the mssim protocol is the standard, being part of the
> reference implementation, but practically it's terrible:  Using two

... and it's missing functionality related to state migration

> ports per vTPM is hardly scalable in a cloud situation and, as you say,
> it has no security.  Ideally someone with TCG connections would try to
> standardize a more scalable network server protocol, something nicely
> rest based that identified the vTPM by say its EK name.
> 
> James
>
diff mbox series

Patch

diff --git a/backends/tpm/Kconfig b/backends/tpm/Kconfig
index 5d91eb89c2..d6d6fa53e9 100644
--- a/backends/tpm/Kconfig
+++ b/backends/tpm/Kconfig
@@ -12,3 +12,8 @@  config TPM_EMULATOR
     bool
     default y
     depends on TPM_BACKEND
+
+config TPM_MSSIM
+    bool
+    default y
+    depends on TPM_BACKEND
diff --git a/backends/tpm/meson.build b/backends/tpm/meson.build
index 7f2503f84e..c7c3c79125 100644
--- a/backends/tpm/meson.build
+++ b/backends/tpm/meson.build
@@ -3,4 +3,5 @@  if have_tpm
   softmmu_ss.add(files('tpm_util.c'))
   softmmu_ss.add(when: 'CONFIG_TPM_PASSTHROUGH', if_true: files('tpm_passthrough.c'))
   softmmu_ss.add(when: 'CONFIG_TPM_EMULATOR', if_true: files('tpm_emulator.c'))
+  softmmu_ss.add(when: 'CONFIG_TPM_MSSIM', if_true: files('tpm_mssim.c'))
 endif
diff --git a/backends/tpm/tpm_mssim.c b/backends/tpm/tpm_mssim.c
new file mode 100644
index 0000000000..6864b1fbc0
--- /dev/null
+++ b/backends/tpm/tpm_mssim.c
@@ -0,0 +1,266 @@ 
+/*
+ * Emulator TPM driver which connects over the mssim protocol
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Copyright (c) 2022
+ * Author: James Bottomley <jejb@linux.ibm.com>
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qemu/sockets.h"
+
+#include "qapi/clone-visitor.h"
+#include "qapi/qapi-visit-tpm.h"
+
+#include "io/channel-socket.h"
+
+#include "sysemu/tpm_backend.h"
+#include "sysemu/tpm_util.h"
+
+#include "qom/object.h"
+
+#include "tpm_int.h"
+#include "tpm_mssim.h"
+
+#define ERROR_PREFIX "TPM mssim Emulator: "
+
+#define TYPE_TPM_MSSIM "tpm-mssim"
+OBJECT_DECLARE_SIMPLE_TYPE(TPMmssim, TPM_MSSIM)
+
+struct TPMmssim {
+    TPMBackend parent;
+
+    TPMmssimOptions opts;
+
+    QIOChannel *cmd_qc, *ctrl_qc;
+};
+
+static int tpm_send_ctrl(TPMmssim *t, uint32_t cmd, Error **errp)
+{
+    int ret;
+
+    cmd = htonl(cmd);
+    ret = qio_channel_write_all(t->ctrl_qc, (char *)&cmd, sizeof(cmd), errp);
+    if (ret != 0)
+        return ret;
+    ret = qio_channel_read_all(t->ctrl_qc, (char *)&cmd, sizeof(cmd), errp);
+    if (ret != 0)
+        return ret;
+    if (cmd != 0) {
+        error_setg(errp, ERROR_PREFIX "Incorrect ACK recieved on control channel 0x%x\n", cmd);
+        return -1;
+    }
+    return 0;
+}
+
+static void tpm_mssim_instance_init(Object *obj)
+{
+}
+
+static void tpm_mssim_instance_finalize(Object *obj)
+{
+    TPMmssim *t = TPM_MSSIM(obj);
+
+    tpm_send_ctrl(t, TPM_SIGNAL_POWER_OFF, NULL);
+
+    object_unref(OBJECT(t->ctrl_qc));
+    object_unref(OBJECT(t->cmd_qc));
+}
+
+static void tpm_mssim_cancel_cmd(TPMBackend *tb)
+{
+        return;
+}
+
+static TPMVersion tpm_mssim_get_version(TPMBackend *tb)
+{
+    return TPM_VERSION_2_0;
+}
+
+static size_t tpm_mssim_get_buffer_size(TPMBackend *tb)
+{
+    /* TCG standard profile max buffer size */
+    return 4096;
+}
+
+static TpmTypeOptions *tpm_mssim_get_opts(TPMBackend *tb)
+{
+    TPMmssim *t = TPM_MSSIM(tb);
+    TpmTypeOptions *opts = g_new0(TpmTypeOptions, 1);
+
+    opts->type = TPM_TYPE_MSSIM;
+    opts->u.mssim.data = QAPI_CLONE(TPMmssimOptions, &t->opts);
+
+    return opts;
+}
+
+static void tpm_mssim_handle_request(TPMBackend *tb, TPMBackendCmd *cmd,
+                                     Error **errp)
+{
+    TPMmssim *t = TPM_MSSIM(tb);
+    uint32_t header, len;
+    uint8_t locality = cmd->locty;
+    struct iovec iov[4];
+    int ret;
+
+    header = htonl(TPM_SEND_COMMAND);
+    len = htonl(cmd->in_len);
+
+    iov[0].iov_base = &header;
+    iov[0].iov_len = sizeof(header);
+    iov[1].iov_base = &locality;
+    iov[1].iov_len = sizeof(locality);
+    iov[2].iov_base = &len;
+    iov[2].iov_len = sizeof(len);
+    iov[3].iov_base = (void *)cmd->in;
+    iov[3].iov_len = cmd->in_len;
+
+    ret = qio_channel_writev_all(t->cmd_qc, iov, 4, errp);
+    if (ret != 0)
+        goto fail;
+
+    ret = qio_channel_read_all(t->cmd_qc, (char *)&len, sizeof(len), errp);
+    if (ret != 0)
+        goto fail;
+    len = ntohl(len);
+    if (len > cmd->out_len) {
+        error_setg(errp, "receive size is too large");
+        goto fail;
+    }
+    ret = qio_channel_read_all(t->cmd_qc, (char *)cmd->out, len, errp);
+    if (ret != 0)
+        goto fail;
+    /* ACK packet */
+    ret = qio_channel_read_all(t->cmd_qc, (char *)&header, sizeof(header), errp);
+    if (ret != 0)
+        goto fail;
+    if (header != 0) {
+        error_setg(errp, "incorrect ACK received on command channel 0x%x", len);
+        goto fail;
+    }
+
+    return;
+
+ fail:
+    error_prepend(errp, ERROR_PREFIX);
+    tpm_util_write_fatal_error_response(cmd->out, cmd->out_len);
+}
+
+static TPMBackend *tpm_mssim_create(QemuOpts *opts)
+{
+    TPMBackend *be = TPM_BACKEND(object_new(TYPE_TPM_MSSIM));
+    TPMmssim *t = TPM_MSSIM(be);
+    InetSocketAddress cmd_s, ctl_s;
+    int sock;
+    const char *host, *port, *ctrl;
+    Error *errp = NULL;
+
+    host = qemu_opt_get(opts, "host");
+    if (!host)
+        host = "localhost";
+    t->opts.host = g_strdup(host);
+
+    port = qemu_opt_get(opts, "port");
+    if (!port)
+        port = "2321";
+    t->opts.port = g_strdup(port);
+
+    ctrl = qemu_opt_get(opts, "ctrl");
+    if (!ctrl)
+        ctrl = "2322";
+    t->opts.ctrl = g_strdup(ctrl);
+
+    cmd_s.host = (char *)host;
+    cmd_s.port = (char *)port;
+
+    ctl_s.host = (char *)host;
+    ctl_s.port = (char *)ctrl;
+
+    sock = inet_connect_saddr(&cmd_s, &errp);
+    if (sock < 0)
+        goto fail;
+    t->cmd_qc = QIO_CHANNEL(qio_channel_socket_new_fd(sock, &errp));
+    if (errp)
+        goto fail;
+    sock = inet_connect_saddr(&ctl_s, &errp);
+    if (sock < 0)
+        goto fail_unref_cmd;
+    t->ctrl_qc = QIO_CHANNEL(qio_channel_socket_new_fd(sock, &errp));
+    if (errp)
+        goto fail_unref_cmd;
+
+    /* reset the TPM using a power cycle sequence, in case someone
+     * has previously powered it up */
+    sock = tpm_send_ctrl(t, TPM_SIGNAL_POWER_OFF, &errp);
+    if (sock != 0)
+        goto fail_unref;
+    sock = tpm_send_ctrl(t, TPM_SIGNAL_POWER_ON, &errp);
+    if (sock != 0)
+        goto fail_unref;
+    sock = tpm_send_ctrl(t, TPM_SIGNAL_NV_ON, &errp);
+    if (sock != 0)
+        goto fail_unref;
+
+    return be;
+ fail_unref:
+    object_unref(OBJECT(t->ctrl_qc));
+ fail_unref_cmd:
+    object_unref(OBJECT(t->cmd_qc));
+ fail:
+    error_prepend(&errp, ERROR_PREFIX);
+    error_report_err(errp);
+    object_unref(OBJECT(be));
+
+    return NULL;
+}
+
+static const QemuOptDesc tpm_mssim_cmdline_opts[] = {
+    TPM_STANDARD_CMDLINE_OPTS,
+    {
+        .name = "host",
+        .type = QEMU_OPT_STRING,
+        .help = "name or IP address of host to connect to (deault localhost)",
+    },
+    {
+        .name = "port",
+        .type = QEMU_OPT_STRING,
+        .help = "port number for standard TPM commands (default 2321)",
+    },
+    {
+        .name = "ctrl",
+        .type = QEMU_OPT_STRING,
+        .help = "control port for TPM commands (default 2322)",
+    },
+};
+
+static void tpm_mssim_class_init(ObjectClass *klass, void *data)
+{
+    TPMBackendClass *cl = TPM_BACKEND_CLASS(klass);
+
+    cl->type = TPM_TYPE_MSSIM;
+    cl->opts = tpm_mssim_cmdline_opts;
+    cl->desc = "TPM mssim emulator backend driver";
+    cl->create = tpm_mssim_create;
+    cl->cancel_cmd = tpm_mssim_cancel_cmd;
+    cl->get_tpm_version = tpm_mssim_get_version;
+    cl->get_buffer_size = tpm_mssim_get_buffer_size;
+    cl->get_tpm_options = tpm_mssim_get_opts;
+    cl->handle_request = tpm_mssim_handle_request;
+}
+
+static const TypeInfo tpm_mssim_info = {
+    .name = TYPE_TPM_MSSIM,
+    .parent = TYPE_TPM_BACKEND,
+    .instance_size = sizeof(TPMmssim),
+    .class_init = tpm_mssim_class_init,
+    .instance_init = tpm_mssim_instance_init,
+    .instance_finalize = tpm_mssim_instance_finalize,
+};
+
+static void tpm_mssim_register(void)
+{
+    type_register_static(&tpm_mssim_info);
+}
+
+type_init(tpm_mssim_register)
diff --git a/backends/tpm/tpm_mssim.h b/backends/tpm/tpm_mssim.h
new file mode 100644
index 0000000000..04a270338a
--- /dev/null
+++ b/backends/tpm/tpm_mssim.h
@@ -0,0 +1,43 @@ 
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * The code below is copied from the Microsoft/TCG Reference implementation
+ *
+ *  https://github.com/Microsoft/ms-tpm-20-ref.git
+ *
+ * In file TPMCmd/Simulator/include/TpmTcpProtocol.h
+ */
+
+#define TPM_SIGNAL_POWER_ON         1
+#define TPM_SIGNAL_POWER_OFF        2
+#define TPM_SIGNAL_PHYS_PRES_ON     3
+#define TPM_SIGNAL_PHYS_PRES_OFF    4
+#define TPM_SIGNAL_HASH_START       5
+#define TPM_SIGNAL_HASH_DATA        6
+        // {uint32_t BufferSize, uint8_t[BufferSize] Buffer}
+#define TPM_SIGNAL_HASH_END         7
+#define TPM_SEND_COMMAND            8
+        // {uint8_t Locality, uint32_t InBufferSize, uint8_t[InBufferSize] InBuffer} ->
+        //     {uint32_t OutBufferSize, uint8_t[OutBufferSize] OutBuffer}
+
+#define TPM_SIGNAL_CANCEL_ON        9
+#define TPM_SIGNAL_CANCEL_OFF       10
+#define TPM_SIGNAL_NV_ON            11
+#define TPM_SIGNAL_NV_OFF           12
+#define TPM_SIGNAL_KEY_CACHE_ON     13
+#define TPM_SIGNAL_KEY_CACHE_OFF    14
+
+#define TPM_REMOTE_HANDSHAKE        15
+#define TPM_SET_ALTERNATIVE_RESULT  16
+
+#define TPM_SIGNAL_RESET            17
+#define TPM_SIGNAL_RESTART          18
+
+#define TPM_SESSION_END             20
+#define TPM_STOP                    21
+
+#define TPM_GET_COMMAND_RESPONSE_SIZES  25
+
+#define TPM_ACT_GET_SIGNALED        26
+
+#define TPM_TEST_FAILURE_MODE       30
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
index 01b789a79e..f4cd030eab 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -841,6 +841,7 @@  void hmp_info_tpm(Monitor *mon, const QDict *qdict)
     unsigned int c = 0;
     TPMPassthroughOptions *tpo;
     TPMEmulatorOptions *teo;
+    TPMmssimOptions *tmo;
 
     info_list = qmp_query_tpm(&err);
     if (err) {
@@ -874,6 +875,11 @@  void hmp_info_tpm(Monitor *mon, const QDict *qdict)
             teo = ti->options->u.emulator.data;
             monitor_printf(mon, ",chardev=%s", teo->chardev);
             break;
+        case TPM_TYPE_MSSIM:
+            tmo = ti->options->u.mssim.data;
+            monitor_printf(mon, ",host=%s,port=%s,ctl=%s", tmo->host,
+                           tmo->port, tmo->host);
+            break;
         case TPM_TYPE__MAX:
             break;
         }
diff --git a/qapi/tpm.json b/qapi/tpm.json
index 4e2ea9756a..d92065043e 100644
--- a/qapi/tpm.json
+++ b/qapi/tpm.json
@@ -49,7 +49,7 @@ 
 #
 # Since: 1.5
 ##
-{ 'enum': 'TpmType', 'data': [ 'passthrough', 'emulator' ],
+{ 'enum': 'TpmType', 'data': [ 'passthrough', 'emulator', 'mssim' ],
   'if': 'CONFIG_TPM' }
 
 ##
@@ -64,7 +64,7 @@ 
 # Example:
 #
 # -> { "execute": "query-tpm-types" }
-# <- { "return": [ "passthrough", "emulator" ] }
+# <- { "return": [ "passthrough", "emulator", "mssim" ] }
 #
 ##
 { 'command': 'query-tpm-types', 'returns': ['TpmType'],
@@ -99,6 +99,24 @@ 
 { 'struct': 'TPMEmulatorOptions', 'data': { 'chardev' : 'str' },
   'if': 'CONFIG_TPM' }
 
+##
+# @TPMmssimOptions:
+#
+# Information for the mssim emulator connection
+#
+# @host: host name or IP address to connect to
+# @port: port for the standard TPM commands
+# @ctrl: control port for TPM state changes
+#
+# Since: 7.2.0
+##
+{ 'struct': 'TPMmssimOptions',
+  'data': {
+      'host': 'str',
+      'port': 'str',
+      'ctrl': 'str' },
+  'if': 'CONFIG_TPM' }
+
 ##
 # @TPMPassthroughOptionsWrapper:
 #
@@ -117,6 +135,15 @@ 
   'data': { 'data': 'TPMEmulatorOptions' },
   'if': 'CONFIG_TPM' }
 
+##
+# @TPMmssimOptionsWrapper:
+#
+# Since: 7.2.0
+##
+{ 'struct': 'TPMmssimOptionsWrapper',
+  'data' : { 'data': 'TPMmssimOptions' },
+  'if': 'CONFIG_TPM' }
+
 ##
 # @TpmTypeOptions:
 #
@@ -124,6 +151,7 @@ 
 #
 # @type: - 'passthrough' The configuration options for the TPM passthrough type
 #        - 'emulator' The configuration options for TPM emulator backend type
+#        - 'mssim' The configuration options for TPM emulator mssim type
 #
 # Since: 1.5
 ##
@@ -131,7 +159,8 @@ 
   'base': { 'type': 'TpmType' },
   'discriminator': 'type',
   'data': { 'passthrough' : 'TPMPassthroughOptionsWrapper',
-            'emulator': 'TPMEmulatorOptionsWrapper' },
+            'emulator': 'TPMEmulatorOptionsWrapper',
+            'mssim': 'TPMmssimOptionsWrapper' },
   'if': 'CONFIG_TPM' }
 
 ##