qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
To: "Daniel P. Berrange" <berrange@redhat.com>
Cc: Juan Quintela <quintela@redhat.com>,
	qemu-devel@nongnu.org, Gerd Hoffmann <kraxel@redhat.com>,
	Amit Shah <amit.shah@redhat.com>,
	Paolo Bonzini <pbonzini@redhat.com>
Subject: Re: [Qemu-devel] [PATCH FYI 12/46] io: add QIOChannelTLS class
Date: Mon, 7 Sep 2015 16:31:08 +0100	[thread overview]
Message-ID: <20150907153107.GD2337@work-vm> (raw)
In-Reply-To: <1441294768-8712-13-git-send-email-berrange@redhat.com>

* Daniel P. Berrange (berrange@redhat.com) wrote:
> Add a QIOChannel subclass that can run the TLS protocol over
> the top of another QIOChannel instance. The object provides a
> simplified API to perform the handshake when starting the TLS
> session. The layering of TLS over the underlying channel does
> not have to be setup immediately. It is possible to take an
> existing QIOChannel that has done some handshake and then swap
> in the QIOChannelTLS layer. This allows for use with protocols
> which start TLS right away, and those which start plain text
> and then negotiate TLS.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>

> ---
> +#ifdef QIO_DEBUG
> +#define DPRINTF(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
> +#else
> +#define DPRINTF(fmt, ...) do { } while (0)
> +#endif

Can you use the trace_ stuff rather than dprintf's; I've been trying
to remove them all from the migration code (and with trace configured in
stderr mode it works pretty easily).

On a different question; if this TLS channel is backed by a socket, can I do
a shutdown call that will bubble down to the socket?

Dave

> +
> +
> +static ssize_t qio_channel_tls_write_handler(const char *buf,
> +                                             size_t len,
> +                                             void *opaque)
> +{
> +    QIOChannelTLS *tioc = QIO_CHANNEL_TLS(opaque);
> +    ssize_t ret;
> +
> +    ret = qio_channel_write(tioc->master, buf, len, NULL);
> +    if (ret == QIO_CHANNEL_ERR_BLOCK) {
> +        errno = EAGAIN;
> +        return -1;
> +    } else if (ret < 0) {
> +        errno = EIO;
> +        return -1;
> +    }
> +    return ret;
> +}
> +
> +static ssize_t qio_channel_tls_read_handler(char *buf,
> +                                            size_t len,
> +                                            void *opaque)
> +{
> +    QIOChannelTLS *tioc = QIO_CHANNEL_TLS(opaque);
> +    ssize_t ret;
> +
> +    ret = qio_channel_read(tioc->master, buf, len, NULL);
> +    if (ret == QIO_CHANNEL_ERR_BLOCK) {
> +        errno = EAGAIN;
> +        return -1;
> +    } else if (ret < 0) {
> +        errno = EIO;
> +        return -1;
> +    }
> +    return ret;
> +}
> +
> +
> +QIOChannelTLS *
> +qio_channel_tls_new_server(QIOChannel *master,
> +                           QCryptoTLSCreds *creds,
> +                           const char *aclname,
> +                           Error **errp)
> +{
> +    QIOChannelTLS *ioc;
> +
> +    ioc = QIO_CHANNEL_TLS(object_new(TYPE_QIO_CHANNEL_TLS));
> +
> +    ioc->master = master;
> +    object_ref(OBJECT(master));
> +
> +    ioc->session = qcrypto_tls_session_new(
> +        creds,
> +        NULL,
> +        aclname,
> +        QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
> +        errp);
> +    if (!ioc->session) {
> +        goto error;
> +    }
> +
> +    qcrypto_tls_session_set_callbacks(
> +        ioc->session,
> +        qio_channel_tls_write_handler,
> +        qio_channel_tls_read_handler,
> +        ioc);
> +
> +    return ioc;
> +
> + error:
> +    DPRINTF("Session setup failed %s\n",
> +            error_get_pretty(*errp));
> +    object_unref(OBJECT(ioc));
> +    return NULL;
> +}
> +
> +QIOChannelTLS *
> +qio_channel_tls_new_client(QIOChannel *master,
> +                           QCryptoTLSCreds *creds,
> +                           const char *hostname,
> +                           Error **errp)
> +{
> +    QIOChannelTLS *ioc;
> +
> +    ioc = QIO_CHANNEL_TLS(object_new(TYPE_QIO_CHANNEL_TLS));
> +
> +    ioc->master = master;
> +    object_ref(OBJECT(master));
> +
> +    ioc->session = qcrypto_tls_session_new(
> +        creds,
> +        hostname,
> +        NULL,
> +        QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT,
> +        errp);
> +    if (!ioc->session) {
> +        goto error;
> +    }
> +
> +    qcrypto_tls_session_set_callbacks(
> +        ioc->session,
> +        qio_channel_tls_write_handler,
> +        qio_channel_tls_read_handler,
> +        ioc);
> +
> +    return ioc;
> +
> + error:
> +    DPRINTF("Session setup failed %s\n",
> +            error_get_pretty(*errp));
> +    object_unref(OBJECT(ioc));
> +    return NULL;
> +}
> +
> +
> +static gboolean qio_channel_tls_handshake_io(QIOChannel *ioc,
> +                                             GIOCondition condition,
> +                                             gpointer user_data);
> +
> +static void qio_channel_tls_handshake_task(QIOChannelTLS *ioc,
> +                                           QIOTask *task)
> +{
> +    Error *err = NULL;
> +    QCryptoTLSSessionHandshakeStatus status;
> +
> +    if (qcrypto_tls_session_handshake(ioc->session, &err) < 0) {
> +        qio_task_abort(task, err);
> +        goto cleanup;
> +    }
> +
> +    status = qcrypto_tls_session_get_handshake_status(ioc->session);
> +    if (status == QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
> +        if (qcrypto_tls_session_check_credentials(ioc->session,
> +                                                  &err) < 0) {
> +            DPRINTF("Check creds failed session=%p err=%s\n",
> +                    ioc->session, error_get_pretty(err));
> +            qio_task_abort(task, err);
> +            goto cleanup;
> +        }
> +        DPRINTF("Handshake compelte session=%p\n",
> +                ioc->session);
> +        qio_task_complete(task);
> +    } else {
> +        GIOCondition condition;
> +        DPRINTF("Handshake still running %d\n", status);
> +        if (status == QCRYPTO_TLS_HANDSHAKE_SENDING) {
> +            condition = G_IO_OUT;
> +        } else {
> +            condition = G_IO_IN;
> +        }
> +
> +        qio_channel_add_watch(ioc->master,
> +                              condition,
> +                              qio_channel_tls_handshake_io,
> +                              task,
> +                              NULL);
> +    }
> +
> + cleanup:
> +    error_free(err);
> +}
> +
> +
> +static gboolean qio_channel_tls_handshake_io(QIOChannel *ioc,
> +                                             GIOCondition condition,
> +                                             gpointer user_data)
> +{
> +    QIOTask *task = user_data;
> +    QIOChannelTLS *tioc = QIO_CHANNEL_TLS(
> +        qio_task_get_source(task));
> +
> +    qio_channel_tls_handshake_task(
> +       tioc, task);
> +
> +    object_unref(OBJECT(tioc));
> +
> +    return FALSE;
> +}
> +
> +void qio_channel_tls_handshake(QIOChannelTLS *ioc,
> +                               QIOTaskFunc func,
> +                               gpointer opaque,
> +                               GDestroyNotify destroy)
> +{
> +    QIOTask *task;
> +
> +    task = qio_task_new(OBJECT(ioc),
> +                        func, opaque, destroy);
> +
> +    qio_channel_tls_handshake_task(ioc, task);
> +}
> +
> +
> +static void qio_channel_tls_init(Object *obj G_GNUC_UNUSED)
> +{
> +}
> +
> +
> +static void qio_channel_tls_finalize(Object *obj)
> +{
> +    QIOChannelTLS *ioc = QIO_CHANNEL_TLS(obj);
> +
> +    object_unref(OBJECT(ioc->master));
> +    qcrypto_tls_session_free(ioc->session);
> +}
> +
> +
> +static ssize_t qio_channel_tls_readv(QIOChannel *ioc,
> +                                     const struct iovec *iov,
> +                                     size_t niov,
> +                                     int **fds,
> +                                     size_t *nfds,
> +                                     Error **errp)
> +{
> +    QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
> +    size_t i;
> +    ssize_t got = 0;
> +
> +    if (fds || nfds) {
> +        error_setg(errp, "%s",
> +                   _("Cannot receive file descriptors over TLS channel"));
> +        return -1;
> +    }
> +
> +    for (i = 0 ; i < niov ; i++) {
> +        ssize_t ret = qcrypto_tls_session_read(tioc->session,
> +                                               iov[i].iov_base,
> +                                               iov[i].iov_len);
> +        if (ret < 0) {
> +            if (errno == EAGAIN) {
> +                if (got) {
> +                    return got;
> +                } else {
> +                    return QIO_CHANNEL_ERR_BLOCK;
> +                }
> +            }
> +
> +            error_setg_errno(errp, errno, "%s",
> +                             _("Cannot read from TLS channel"));
> +            return -1;
> +        }
> +        got += ret;
> +        if (ret < iov[i].iov_len) {
> +            break;
> +        }
> +    }
> +    return got;
> +}
> +
> +
> +static ssize_t qio_channel_tls_writev(QIOChannel *ioc,
> +                                      const struct iovec *iov,
> +                                      size_t niov,
> +                                      int *fds,
> +                                      size_t nfds,
> +                                      Error **errp)
> +{
> +    QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
> +    size_t i;
> +    ssize_t done = 0;
> +
> +    if (fds || nfds) {
> +        error_setg(errp, "%s",
> +                   _("Cannot send file descriptors over TLS channel"));
> +        return -1;
> +    }
> +
> +    for (i = 0 ; i < niov ; i++) {
> +        ssize_t ret = qcrypto_tls_session_write(tioc->session,
> +                                                iov[i].iov_base,
> +                                                iov[i].iov_len);
> +        if (ret <= 0) {
> +            if (errno == EAGAIN) {
> +                if (done) {
> +                    return done;
> +                } else {
> +                    return QIO_CHANNEL_ERR_BLOCK;
> +                }
> +            }
> +
> +            error_setg_errno(errp, errno, "%s",
> +                             _("Cannot write to TLS channel"));
> +            return -1;
> +        }
> +        done += ret;
> +        if (ret < iov[i].iov_len) {
> +            break;
> +        }
> +    }
> +    return done;
> +}
> +
> +static void qio_channel_tls_set_blocking(QIOChannel *ioc,
> +                                         bool enabled)
> +{
> +    QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
> +
> +    qio_channel_set_blocking(tioc->master, enabled);
> +}
> +
> +static int qio_channel_tls_close(QIOChannel *ioc,
> +                                 Error **errp)
> +{
> +    QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
> +
> +    return qio_channel_close(tioc->master, errp);
> +}
> +
> +static GSource *qio_channel_tls_create_watch(QIOChannel *ioc,
> +                                             GIOCondition condition)
> +{
> +    QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
> +
> +    return qio_channel_create_watch(tioc->master, condition);
> +}
> +
> +QCryptoTLSSession *
> +qio_channel_tls_get_session(QIOChannelTLS *ioc)
> +{
> +    return ioc->session;
> +}
> +
> +static void qio_channel_tls_class_init(ObjectClass *klass,
> +                                       void *class_data G_GNUC_UNUSED)
> +{
> +    QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
> +
> +    ioc_klass->io_writev = qio_channel_tls_writev;
> +    ioc_klass->io_readv = qio_channel_tls_readv;
> +    ioc_klass->io_set_blocking = qio_channel_tls_set_blocking;
> +    ioc_klass->io_close = qio_channel_tls_close;
> +    ioc_klass->io_create_watch = qio_channel_tls_create_watch;
> +}
> +
> +static const TypeInfo qio_channel_tls_info = {
> +    .parent = TYPE_QIO_CHANNEL,
> +    .name = TYPE_QIO_CHANNEL_TLS,
> +    .instance_size = sizeof(QIOChannelTLS),
> +    .instance_init = qio_channel_tls_init,
> +    .instance_finalize = qio_channel_tls_finalize,
> +    .class_init = qio_channel_tls_class_init,
> +};
> +
> +static void qio_channel_tls_register_types(void)
> +{
> +    type_register_static(&qio_channel_tls_info);
> +}
> +
> +type_init(qio_channel_tls_register_types);
> diff --git a/tests/.gitignore b/tests/.gitignore
> index bb66d94..aa90bb2 100644
> --- a/tests/.gitignore
> +++ b/tests/.gitignore
> @@ -26,6 +26,7 @@ test-iov
>  test-io-channel-file
>  test-io-channel-file.txt
>  test-io-channel-socket
> +test-io-channel-tls
>  test-io-task
>  test-mul64
>  test-opts-visitor
> diff --git a/tests/Makefile b/tests/Makefile
> index f896051..8138362 100644
> --- a/tests/Makefile
> +++ b/tests/Makefile
> @@ -81,6 +81,7 @@ check-unit-$(CONFIG_GNUTLS) += tests/test-crypto-tlssession$(EXESUF)
>  check-unit-y += tests/test-io-task$(EXESUF)
>  check-unit-y += tests/test-io-channel-socket$(EXESUF)
>  check-unit-y += tests/test-io-channel-file$(EXESUF)
> +check-unit-$(CONFIG_GNUTLS) += tests/test-io-channel-tls$(EXESUF)
>  
>  check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
>  
> @@ -366,6 +367,9 @@ tests/test-io-channel-socket$(EXESUF): tests/test-io-channel-socket.o \
>          tests/io-channel-helpers.o $(test-io-obj-y)
>  tests/test-io-channel-file$(EXESUF): tests/test-io-channel-file.o \
>          tests/io-channel-helpers.o $(test-io-obj-y)
> +tests/test-io-channel-tls$(EXESUF): tests/test-io-channel-tls.o \
> +	tests/crypto-tls-x509-helpers.o tests/pkix_asn1_tab.o \
> +	tests/io-channel-helpers.o $(test-io-obj-y)
>  
>  libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o tests/libqos/malloc.o
>  libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
> diff --git a/tests/test-io-channel-tls.c b/tests/test-io-channel-tls.c
> new file mode 100644
> index 0000000..75a1396
> --- /dev/null
> +++ b/tests/test-io-channel-tls.c
> @@ -0,0 +1,335 @@
> +/*
> + * Copyright (C) 2015 Red Hat, Inc.
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library.  If not, see
> + * <http://www.gnu.org/licenses/>.
> + *
> + * Author: Daniel P. Berrange <berrange@redhat.com>
> + */
> +
> +
> +#include <stdlib.h>
> +#include <fcntl.h>
> +
> +#include "config-host.h"
> +#include "crypto-tls-x509-helpers.h"
> +#include "io/channel-tls.h"
> +#include "io/channel-socket.h"
> +#include "io-channel-helpers.h"
> +#include "crypto/tlscredsx509.h"
> +#include "qemu/acl.h"
> +#include "qom/object_interfaces.h"
> +
> +#ifdef QCRYPTO_HAVE_TLS_TEST_SUPPORT
> +
> +#define WORKDIR "tests/test-io-channel-tls-work/"
> +#define KEYFILE WORKDIR "key-ctx.pem"
> +
> +struct QIOChannelTLSTestData {
> +    const char *servercacrt;
> +    const char *clientcacrt;
> +    const char *servercrt;
> +    const char *clientcrt;
> +    bool expectServerFail;
> +    bool expectClientFail;
> +    const char *hostname;
> +    const char *const *wildcards;
> +};
> +
> +struct QIOChannelTLSHandshakeData {
> +    bool finished;
> +    bool failed;
> +};
> +
> +static void test_tls_handshake_done(Object *source,
> +                                    Error *err,
> +                                    gpointer opaque)
> +{
> +    struct QIOChannelTLSHandshakeData *data = opaque;
> +
> +    data->finished = true;
> +    data->failed = err != NULL;
> +}
> +
> +
> +static QCryptoTLSCreds *test_tls_creds_create(QCryptoTLSCredsEndpoint endpoint,
> +                                              const char *certdir,
> +                                              Error **errp)
> +{
> +    Object *parent = object_get_objects_root();
> +    Object *creds = object_new_with_props(
> +        TYPE_QCRYPTO_TLS_CREDS_X509,
> +        parent,
> +        (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER ?
> +         "testtlscredsserver" : "testtlscredsclient"),
> +        errp,
> +        "endpoint", (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER ?
> +                     "server" : "client"),
> +        "dir", certdir,
> +        "verify-peer", "yes",
> +        /* We skip initial sanity checks here because we
> +         * want to make sure that problems are being
> +         * detected at the TLS session validation stage,
> +         * and the test-crypto-tlscreds test already
> +         * validate the sanity check code.
> +         */
> +        "sanity-check", "no",
> +        NULL
> +        );
> +
> +    if (*errp) {
> +        return NULL;
> +    }
> +    return QCRYPTO_TLS_CREDS(creds);
> +}
> +
> +
> +/*
> + * This tests validation checking of peer certificates
> + *
> + * This is replicating the checks that are done for an
> + * active TLS session after handshake completes. To
> + * simulate that we create our TLS contexts, skipping
> + * sanity checks. When then get a socketpair, and
> + * initiate a TLS session across them. Finally do
> + * do actual cert validation tests
> + */
> +static void test_io_channel_tls(const void *opaque)
> +{
> +    struct QIOChannelTLSTestData *data =
> +        (struct QIOChannelTLSTestData *)opaque;
> +    QCryptoTLSCreds *clientCreds;
> +    QCryptoTLSCreds *serverCreds;
> +    QIOChannelTLS *clientChanTLS;
> +    QIOChannelTLS *serverChanTLS;
> +    QIOChannelSocket *clientChanSock;
> +    QIOChannelSocket *serverChanSock;
> +    qemu_acl *acl;
> +    const char * const *wildcards;
> +    int channel[2];
> +    struct QIOChannelTLSHandshakeData clientHandshake = { false, false };
> +    struct QIOChannelTLSHandshakeData serverHandshake = { false, false };
> +    Error *err = NULL;
> +    GMainContext *mainloop;
> +
> +    /* We'll use this for our fake client-server connection */
> +    g_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, channel) == 0);
> +
> +#define CLIENT_CERT_DIR "tests/test-crypto-tlssession-client/"
> +#define SERVER_CERT_DIR "tests/test-crypto-tlssession-server/"
> +    mkdir(CLIENT_CERT_DIR, 0700);
> +    mkdir(SERVER_CERT_DIR, 0700);
> +
> +    unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT);
> +    unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT);
> +    unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY);
> +
> +    unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT);
> +    unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT);
> +    unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY);
> +
> +    g_assert(link(data->servercacrt,
> +                  SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT) == 0);
> +    g_assert(link(data->servercrt,
> +                  SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT) == 0);
> +    g_assert(link(KEYFILE,
> +                  SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY) == 0);
> +
> +    g_assert(link(data->clientcacrt,
> +                  CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT) == 0);
> +    g_assert(link(data->clientcrt,
> +                  CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT) == 0);
> +    g_assert(link(KEYFILE,
> +                  CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY) == 0);
> +
> +    clientCreds = test_tls_creds_create(
> +        QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT,
> +        CLIENT_CERT_DIR,
> +        &err);
> +    g_assert(clientCreds != NULL);
> +
> +    serverCreds = test_tls_creds_create(
> +        QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
> +        SERVER_CERT_DIR,
> +        &err);
> +    g_assert(serverCreds != NULL);
> +
> +    acl = qemu_acl_init("channeltlsacl");
> +    qemu_acl_reset(acl);
> +    wildcards = data->wildcards;
> +    while (wildcards && *wildcards) {
> +        qemu_acl_append(acl, 0, *wildcards);
> +        wildcards++;
> +    }
> +
> +    clientChanSock = qio_channel_socket_new_fd(
> +        channel[0], &err);
> +    g_assert(clientChanSock != NULL);
> +    serverChanSock = qio_channel_socket_new_fd(
> +        channel[1], &err);
> +    g_assert(serverChanSock != NULL);
> +
> +    /*
> +     * We have an evil loop to do the handshake in a single
> +     * thread, so we need these non-blocking to avoid deadlock
> +     * of ourselves
> +     */
> +    qio_channel_set_blocking(QIO_CHANNEL(clientChanSock), false);
> +    qio_channel_set_blocking(QIO_CHANNEL(serverChanSock), false);
> +
> +    /* Now the real part of the test, setup the sessions */
> +    clientChanTLS = qio_channel_tls_new_client(
> +        QIO_CHANNEL(clientChanSock), clientCreds,
> +        data->hostname, &err);
> +    g_assert(clientChanTLS != NULL);
> +
> +    serverChanTLS = qio_channel_tls_new_server(
> +        QIO_CHANNEL(serverChanSock), serverCreds,
> +        "channeltlsacl", &err);
> +    g_assert(serverChanTLS != NULL);
> +
> +    qio_channel_tls_handshake(clientChanTLS,
> +                              test_tls_handshake_done,
> +                              &clientHandshake,
> +                              NULL);
> +    qio_channel_tls_handshake(serverChanTLS,
> +                              test_tls_handshake_done,
> +                              &serverHandshake,
> +                              NULL);
> +
> +    /*
> +     * Finally we loop around & around doing handshake on each
> +     * session until we get an error, or the handshake completes.
> +     * This relies on the socketpair being nonblocking to avoid
> +     * deadlocking ourselves upon handshake
> +     */
> +    mainloop = g_main_context_default();
> +    do {
> +        g_main_context_iteration(mainloop, TRUE);
> +    } while (!clientHandshake.finished &&
> +             !serverHandshake.finished);
> +
> +    g_assert(clientHandshake.failed == data->expectClientFail);
> +    g_assert(serverHandshake.failed == data->expectServerFail);
> +
> +    test_io_channel_comms(false,
> +                          QIO_CHANNEL(clientChanTLS),
> +                          QIO_CHANNEL(serverChanTLS));
> +
> +    test_io_channel_comms(true,
> +                          QIO_CHANNEL(clientChanTLS),
> +                          QIO_CHANNEL(serverChanTLS));
> +
> +    unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT);
> +    unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT);
> +    unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY);
> +
> +    unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT);
> +    unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT);
> +    unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY);
> +
> +    rmdir(CLIENT_CERT_DIR);
> +    rmdir(SERVER_CERT_DIR);
> +
> +    object_unparent(OBJECT(serverCreds));
> +    object_unparent(OBJECT(clientCreds));
> +
> +    object_unref(OBJECT(serverChanTLS));
> +    object_unref(OBJECT(clientChanTLS));
> +
> +    object_unref(OBJECT(serverChanSock));
> +    object_unref(OBJECT(clientChanSock));
> +
> +    close(channel[0]);
> +    close(channel[1]);
> +}
> +
> +
> +int main(int argc, char **argv)
> +{
> +    int ret;
> +
> +    module_call_init(MODULE_INIT_QOM);
> +    g_test_init(&argc, &argv, NULL);
> +    setenv("GNUTLS_FORCE_FIPS_MODE", "2", 1);
> +
> +    mkdir(WORKDIR, 0700);
> +
> +    test_tls_init(KEYFILE);
> +
> +# define TEST_CHANNEL(name, caCrt,                                      \
> +                      serverCrt, clientCrt,                             \
> +                      expectServerFail, expectClientFail,               \
> +                      hostname, wildcards)                              \
> +    struct QIOChannelTLSTestData name = {                               \
> +        caCrt, caCrt, serverCrt, clientCrt,                             \
> +        expectServerFail, expectClientFail,                             \
> +        hostname, wildcards                                             \
> +    };                                                                  \
> +    g_test_add_data_func("/qio/channel/tls/" # name,                    \
> +                         &name, test_io_channel_tls);
> +
> +    /* A perfect CA, perfect client & perfect server */
> +
> +    /* Basic:CA:critical */
> +    TLS_ROOT_REQ(cacertreq,
> +                 "UK", "qemu CA", NULL, NULL, NULL, NULL,
> +                 true, true, true,
> +                 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
> +                 false, false, NULL, NULL,
> +                 0, 0);
> +    TLS_CERT_REQ(servercertreq, cacertreq,
> +                 "UK", "qemu.org", NULL, NULL, NULL, NULL,
> +                 true, true, false,
> +                 true, true,
> +                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
> +                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
> +                 0, 0);
> +    TLS_CERT_REQ(clientcertreq, cacertreq,
> +                 "UK", "qemu", NULL, NULL, NULL, NULL,
> +                 true, true, false,
> +                 true, true,
> +                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
> +                 true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
> +                 0, 0);
> +
> +    const char *const wildcards[] = {
> +        "C=UK,CN=qemu*",
> +        NULL,
> +    };
> +    TEST_CHANNEL(basic, cacertreq.filename, servercertreq.filename,
> +                 clientcertreq.filename, false, false,
> +                 "qemu.org", wildcards);
> +
> +    ret = g_test_run();
> +
> +    test_tls_discard_cert(&clientcertreq);
> +    test_tls_discard_cert(&servercertreq);
> +    test_tls_discard_cert(&cacertreq);
> +
> +    test_tls_cleanup(KEYFILE);
> +    rmdir(WORKDIR);
> +
> +    return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
> +}
> +
> +#else /* ! QCRYPTO_HAVE_TLS_TEST_SUPPORT */
> +
> +int
> +main(void)
> +{
> +    return EXIT_SUCCESS;
> +}
> +
> +#endif /* ! QCRYPTO_HAVE_TLS_TEST_SUPPORT */
> -- 
> 2.4.3
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

  reply	other threads:[~2015-09-07 15:31 UTC|newest]

Thread overview: 57+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-09-03 15:38 [Qemu-devel] [PATCH FYI 00/46] Generic TLS support across VNC/chardev/migration Daniel P. Berrange
2015-09-03 15:38 ` [Qemu-devel] [PATCH FYI 01/46] sockets: add helpers for creating SocketAddress from a socket Daniel P. Berrange
2015-09-03 15:38 ` [Qemu-devel] [PATCH FYI 02/46] sockets: move qapi_copy_SocketAddress into qemu-sockets.c Daniel P. Berrange
2015-09-03 15:38 ` [Qemu-devel] [PATCH FYI 03/46] sockets: allow port to be NULL when listening on IP address Daniel P. Berrange
2015-09-03 15:38 ` [Qemu-devel] [PATCH FYI 04/46] osdep: add qemu_fork() wrapper for safely handling signals Daniel P. Berrange
2015-09-03 15:38 ` [Qemu-devel] [PATCH FYI 05/46] coroutine: move into libqemuutil.a library Daniel P. Berrange
2015-09-03 15:38 ` [Qemu-devel] [PATCH FYI 06/46] io: add abstract QIOChannel classes Daniel P. Berrange
2015-09-03 15:38 ` [Qemu-devel] [PATCH FYI 07/46] io: add helper module for creating watches on FDs Daniel P. Berrange
2015-09-03 15:38 ` [Qemu-devel] [PATCH FYI 08/46] io: pull Buffer code out of VNC module Daniel P. Berrange
2015-09-03 15:38 ` [Qemu-devel] [PATCH FYI 09/46] io: add QIOTask class for async operations Daniel P. Berrange
2015-09-03 15:38 ` [Qemu-devel] [PATCH FYI 10/46] io: add QIOChannelSocket class Daniel P. Berrange
2015-09-03 15:38 ` [Qemu-devel] [PATCH FYI 11/46] io: add QIOChannelFile class Daniel P. Berrange
2015-09-03 15:38 ` [Qemu-devel] [PATCH FYI 12/46] io: add QIOChannelTLS class Daniel P. Berrange
2015-09-07 15:31   ` Dr. David Alan Gilbert [this message]
2015-09-07 15:41     ` Daniel P. Berrange
2015-09-07 15:51       ` Dr. David Alan Gilbert
2015-09-07 16:04         ` Daniel P. Berrange
2015-09-03 15:38 ` [Qemu-devel] [PATCH FYI 13/46] io: add QIOChannelWebsock class Daniel P. Berrange
2015-09-07 15:44   ` Dr. David Alan Gilbert
2015-09-07 15:50     ` Daniel P. Berrange
2015-09-03 15:38 ` [Qemu-devel] [PATCH FYI 14/46] io: add QIOChannelCommand class Daniel P. Berrange
2015-09-03 15:38 ` [Qemu-devel] [PATCH FYI 15/46] ui: convert VNC startup code to use SocketAddress Daniel P. Berrange
2015-09-03 15:38 ` [Qemu-devel] [PATCH FYI 16/46] ui: convert VNC server to use QIOChannelSocket Daniel P. Berrange
2015-09-03 15:38 ` [Qemu-devel] [PATCH FYI 17/46] ui: convert VNC server to use QIOChannelTLS Daniel P. Berrange
2015-09-03 15:39 ` [Qemu-devel] [PATCH FYI 18/46] ui: convert VNC server to use QIOChannelWebsock Daniel P. Berrange
2015-09-03 15:39 ` [Qemu-devel] [PATCH FYI 19/46] char: remove fixed length filename allocation Daniel P. Berrange
2015-09-03 15:39 ` [Qemu-devel] [PATCH FYI 20/46] char: convert from GIOChannel to QIOChannel Daniel P. Berrange
2015-09-03 15:39 ` [Qemu-devel] [PATCH FYI 21/46] char: don't assume telnet initialization will not block Daniel P. Berrange
2015-09-03 15:39 ` [Qemu-devel] [PATCH FYI 22/46] char: introduce support for TLS encrypted TCP chardev backend Daniel P. Berrange
2015-09-03 15:39 ` [Qemu-devel] [PATCH FYI 23/46] nbd: convert to use the QAPI SocketAddress object Daniel P. Berrange
2015-09-03 15:39 ` [Qemu-devel] [PATCH FYI 24/46] qemu-nbd: " Daniel P. Berrange
2015-09-03 15:39 ` [Qemu-devel] [PATCH FYI 25/46] sockets: remove use of QemuOpts from header file Daniel P. Berrange
2015-09-03 15:39 ` [Qemu-devel] [PATCH FYI 26/46] sockets: remove use of QemuOpts from socket_listen Daniel P. Berrange
2015-09-03 15:39 ` [Qemu-devel] [PATCH FYI 27/46] sockets: remove use of QemuOpts from socket_connect Daniel P. Berrange
2015-09-03 15:39 ` [Qemu-devel] [PATCH FYI 28/46] sockets: remove use of QemuOpts from socket_dgram Daniel P. Berrange
2015-09-03 15:39 ` [Qemu-devel] [PATCH FYI 29/46] migration: remove use of qemu_bufopen from vmstate tests Daniel P. Berrange
2015-09-07 16:08   ` Dr. David Alan Gilbert
2015-09-07 16:17     ` Daniel P. Berrange
2015-09-03 15:39 ` [Qemu-devel] [PATCH FYI 30/46] migration: remove memory buffer based QEMUFile backend Daniel P. Berrange
2015-09-03 15:39 ` [Qemu-devel] [PATCH FYI 31/46] migration: move definition of struct QEMUFile back into qemu-file.c Daniel P. Berrange
2015-09-03 15:39 ` [Qemu-devel] [PATCH FYI 32/46] migration: split migration hooks out of QEMUFileOps Daniel P. Berrange
2015-09-03 15:39 ` [Qemu-devel] [PATCH FYI 33/46] migration: ensure qemu_fflush() always writes full data amount Daniel P. Berrange
2015-09-03 15:39 ` [Qemu-devel] [PATCH FYI 34/46] migration: introduce qemu_fset_blocking function on QEMUFile Daniel P. Berrange
2015-09-03 15:39 ` [Qemu-devel] [PATCH FYI 35/46] migration: force QEMUFile to blocking mode for outgoing migration Daniel P. Berrange
2015-09-03 15:39 ` [Qemu-devel] [PATCH FYI 36/46] migration: introduce a new QEMUFile impl based on QIOChannel Daniel P. Berrange
2015-09-03 15:39 ` [Qemu-devel] [PATCH FYI 37/46] migration: convert unix socket protocol to use QIOChannel Daniel P. Berrange
2015-09-03 15:39 ` [Qemu-devel] [PATCH FYI 38/46] migration: convert tcp " Daniel P. Berrange
2015-09-03 15:39 ` [Qemu-devel] [PATCH FYI 39/46] migration: convert fd " Daniel P. Berrange
2015-09-03 15:39 ` [Qemu-devel] [PATCH FYI 40/46] migration: convert exec " Daniel P. Berrange
2015-09-03 15:39 ` [Qemu-devel] [PATCH FYI 41/46] migration: convert RDMA to use QIOChannel interface Daniel P. Berrange
2015-09-03 15:39 ` [Qemu-devel] [PATCH FYI 42/46] migration: convert savevm to use QIOChannel for writing to files Daniel P. Berrange
2015-09-03 15:39 ` [Qemu-devel] [PATCH FYI 43/46] migration: delete QEMUFile sockets implementation Daniel P. Berrange
2015-09-03 15:39 ` [Qemu-devel] [PATCH FYI 44/46] migration: delete QEMUFile stdio implementation Daniel P. Berrange
2015-09-03 15:39 ` [Qemu-devel] [PATCH FYI 45/46] migration: support TLS encryption with TCP migration backend Daniel P. Berrange
2015-09-07 16:23   ` Dr. David Alan Gilbert
2015-09-07 16:29     ` Daniel P. Berrange
2015-09-03 15:39 ` [Qemu-devel] [PATCH FYI 46/46] migration: remove support for non-iovec based write handlers Daniel P. Berrange

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=20150907153107.GD2337@work-vm \
    --to=dgilbert@redhat.com \
    --cc=amit.shah@redhat.com \
    --cc=berrange@redhat.com \
    --cc=kraxel@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=quintela@redhat.com \
    /path/to/YOUR_REPLY

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

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