qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH FYI 12/46] io: add QIOChannelTLS class


From: Dr. David Alan Gilbert
Subject: Re: [Qemu-devel] [PATCH FYI 12/46] io: add QIOChannelTLS class
Date: Mon, 7 Sep 2015 16:31:08 +0100
User-agent: Mutt/1.5.23 (2014-03-12)

* Daniel P. Berrange (address@hidden) 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 <address@hidden>

> ---
> +#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 <address@hidden>
> + */
> +
> +
> +#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 / address@hidden / Manchester, UK



reply via email to

[Prev in Thread] Current Thread [Next in Thread]