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
next prev parent 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).