[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
- [Qemu-devel] [PATCH FYI 01/46] sockets: add helpers for creating SocketAddress from a socket, (continued)
- [Qemu-devel] [PATCH FYI 01/46] sockets: add helpers for creating SocketAddress from a socket, Daniel P. Berrange, 2015/09/03
- [Qemu-devel] [PATCH FYI 03/46] sockets: allow port to be NULL when listening on IP address, Daniel P. Berrange, 2015/09/03
- [Qemu-devel] [PATCH FYI 04/46] osdep: add qemu_fork() wrapper for safely handling signals, Daniel P. Berrange, 2015/09/03
- [Qemu-devel] [PATCH FYI 05/46] coroutine: move into libqemuutil.a library, Daniel P. Berrange, 2015/09/03
- [Qemu-devel] [PATCH FYI 06/46] io: add abstract QIOChannel classes, Daniel P. Berrange, 2015/09/03
- [Qemu-devel] [PATCH FYI 08/46] io: pull Buffer code out of VNC module, Daniel P. Berrange, 2015/09/03
- [Qemu-devel] [PATCH FYI 09/46] io: add QIOTask class for async operations, Daniel P. Berrange, 2015/09/03
- [Qemu-devel] [PATCH FYI 11/46] io: add QIOChannelFile class, Daniel P. Berrange, 2015/09/03
- [Qemu-devel] [PATCH FYI 10/46] io: add QIOChannelSocket class, Daniel P. Berrange, 2015/09/03
- [Qemu-devel] [PATCH FYI 12/46] io: add QIOChannelTLS class, Daniel P. Berrange, 2015/09/03
- Re: [Qemu-devel] [PATCH FYI 12/46] io: add QIOChannelTLS class,
Dr. David Alan Gilbert <=
[Qemu-devel] [PATCH FYI 15/46] ui: convert VNC startup code to use SocketAddress, Daniel P. Berrange, 2015/09/03
[Qemu-devel] [PATCH FYI 14/46] io: add QIOChannelCommand class, Daniel P. Berrange, 2015/09/03
[Qemu-devel] [PATCH FYI 13/46] io: add QIOChannelWebsock class, Daniel P. Berrange, 2015/09/03
[Qemu-devel] [PATCH FYI 17/46] ui: convert VNC server to use QIOChannelTLS, Daniel P. Berrange, 2015/09/03
[Qemu-devel] [PATCH FYI 16/46] ui: convert VNC server to use QIOChannelSocket, Daniel P. Berrange, 2015/09/03