render / rpms / qemu

Forked from rpms/qemu 9 months ago
Clone

Blame 05-vnc-tls-vencrypt.patch

Glauber Costa 47b075
Index: qemu-kvm-0.10/qemu/Makefile
Glauber Costa 47b075
===================================================================
Glauber Costa 47b075
--- qemu-kvm-0.10.orig/qemu/Makefile
Glauber Costa 47b075
+++ qemu-kvm-0.10/qemu/Makefile
Glauber Costa 47b075
@@ -149,6 +149,9 @@ ifdef CONFIG_CURSES
Glauber Costa 47b075
 OBJS+=curses.o
Glauber Costa 47b075
 endif
Glauber Costa 47b075
 OBJS+=vnc.o d3des.o
Glauber Costa 47b075
+ifdef CONFIG_VNC_TLS
Glauber Costa 47b075
+OBJS+=vnc-tls.o vnc-auth-vencrypt.o
Glauber Costa 47b075
+endif
Glauber Costa 47b075
 
Glauber Costa 47b075
 ifdef CONFIG_COCOA
Glauber Costa 47b075
 OBJS+=cocoa.o
Glauber Costa 47b075
@@ -172,10 +175,16 @@ sdl.o: sdl.c keymaps.h sdl_keysym.h
Glauber Costa 47b075
 
Glauber Costa 47b075
 sdl.o audio/sdlaudio.o: CFLAGS += $(SDL_CFLAGS)
Glauber Costa 47b075
 
Glauber Costa 47b075
-vnc.o: vnc.c keymaps.h sdl_keysym.h vnchextile.h d3des.c d3des.h
Glauber Costa 47b075
+vnc.h: vnc-tls.h vnc-auth-vencrypt.h keymaps.h
Glauber Costa 47b075
+
Glauber Costa 47b075
+vnc.o: vnc.c vnc.h vnc_keysym.h vnchextile.h d3des.c d3des.h
Glauber Costa 47b075
 
Glauber Costa 47b075
 vnc.o: CFLAGS += $(CONFIG_VNC_TLS_CFLAGS)
Glauber Costa 47b075
 
Glauber Costa 47b075
+vnc-tls.o: vnc-tls.c vnc.h
Glauber Costa 47b075
+
Glauber Costa 47b075
+vnc-auth-vencrypt.o: vnc-auth-vencrypt.c vnc.h
Glauber Costa 47b075
+
Glauber Costa 47b075
 curses.o: curses.c keymaps.h curses_keys.h
Glauber Costa 47b075
 
Glauber Costa 47b075
 bt-host.o: CFLAGS += $(CONFIG_BLUEZ_CFLAGS)
Glauber Costa 47b075
Index: qemu-kvm-0.10/qemu/vnc-auth-vencrypt.c
Glauber Costa 47b075
===================================================================
Glauber Costa 47b075
--- /dev/null
Glauber Costa 47b075
+++ qemu-kvm-0.10/qemu/vnc-auth-vencrypt.c
Glauber Costa 47b075
@@ -0,0 +1,167 @@
Glauber Costa 47b075
+/*
Glauber Costa 47b075
+ * QEMU VNC display driver: VeNCrypt authentication setup
Glauber Costa 47b075
+ *
Glauber Costa 47b075
+ * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
Glauber Costa 47b075
+ * Copyright (C) 2006 Fabrice Bellard
Glauber Costa 47b075
+ * Copyright (C) 2009 Red Hat, Inc
Glauber Costa 47b075
+ *
Glauber Costa 47b075
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
Glauber Costa 47b075
+ * of this software and associated documentation files (the "Software"), to deal
Glauber Costa 47b075
+ * in the Software without restriction, including without limitation the rights
Glauber Costa 47b075
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
Glauber Costa 47b075
+ * copies of the Software, and to permit persons to whom the Software is
Glauber Costa 47b075
+ * furnished to do so, subject to the following conditions:
Glauber Costa 47b075
+ *
Glauber Costa 47b075
+ * The above copyright notice and this permission notice shall be included in
Glauber Costa 47b075
+ * all copies or substantial portions of the Software.
Glauber Costa 47b075
+ *
Glauber Costa 47b075
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Glauber Costa 47b075
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Glauber Costa 47b075
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
Glauber Costa 47b075
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Glauber Costa 47b075
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Glauber Costa 47b075
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
Glauber Costa 47b075
+ * THE SOFTWARE.
Glauber Costa 47b075
+ */
Glauber Costa 47b075
+
Glauber Costa 47b075
+#include "vnc.h"
Glauber Costa 47b075
+
Glauber Costa 47b075
+
Glauber Costa 47b075
+static void start_auth_vencrypt_subauth(VncState *vs)
Glauber Costa 47b075
+{
Glauber Costa 47b075
+    switch (vs->vd->subauth) {
Glauber Costa 47b075
+    case VNC_AUTH_VENCRYPT_TLSNONE:
Glauber Costa 47b075
+    case VNC_AUTH_VENCRYPT_X509NONE:
Glauber Costa 47b075
+       VNC_DEBUG("Accept TLS auth none\n");
Glauber Costa 47b075
+       vnc_write_u32(vs, 0); /* Accept auth completion */
Glauber Costa 47b075
+       start_client_init(vs);
Glauber Costa 47b075
+       break;
Glauber Costa 47b075
+
Glauber Costa 47b075
+    case VNC_AUTH_VENCRYPT_TLSVNC:
Glauber Costa 47b075
+    case VNC_AUTH_VENCRYPT_X509VNC:
Glauber Costa 47b075
+       VNC_DEBUG("Start TLS auth VNC\n");
Glauber Costa 47b075
+       start_auth_vnc(vs);
Glauber Costa 47b075
+       break;
Glauber Costa 47b075
+
Glauber Costa 47b075
+    default: /* Should not be possible, but just in case */
Glauber Costa 47b075
+       VNC_DEBUG("Reject auth %d\n", vs->vd->auth);
Glauber Costa 47b075
+       vnc_write_u8(vs, 1);
Glauber Costa 47b075
+       if (vs->minor >= 8) {
Glauber Costa 47b075
+           static const char err[] = "Unsupported authentication type";
Glauber Costa 47b075
+           vnc_write_u32(vs, sizeof(err));
Glauber Costa 47b075
+           vnc_write(vs, err, sizeof(err));
Glauber Costa 47b075
+       }
Glauber Costa 47b075
+       vnc_client_error(vs);
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+}
Glauber Costa 47b075
+
Glauber Costa 47b075
+static void vnc_tls_handshake_io(void *opaque);
Glauber Costa 47b075
+
Glauber Costa 47b075
+static int vnc_start_vencrypt_handshake(struct VncState *vs) {
Glauber Costa 47b075
+    int ret;
Glauber Costa 47b075
+
Glauber Costa 47b075
+    if ((ret = gnutls_handshake(vs->tls.session)) < 0) {
Glauber Costa 47b075
+       if (!gnutls_error_is_fatal(ret)) {
Glauber Costa 47b075
+           VNC_DEBUG("Handshake interrupted (blocking)\n");
Glauber Costa 47b075
+           if (!gnutls_record_get_direction(vs->tls.session))
Glauber Costa 47b075
+               qemu_set_fd_handler(vs->csock, vnc_tls_handshake_io, NULL, vs);
Glauber Costa 47b075
+           else
Glauber Costa 47b075
+               qemu_set_fd_handler(vs->csock, NULL, vnc_tls_handshake_io, vs);
Glauber Costa 47b075
+           return 0;
Glauber Costa 47b075
+       }
Glauber Costa 47b075
+       VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret));
Glauber Costa 47b075
+       vnc_client_error(vs);
Glauber Costa 47b075
+       return -1;
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+
Glauber Costa 47b075
+    if (vs->vd->tls.x509verify) {
Glauber Costa 47b075
+	if (vnc_tls_validate_certificate(vs) < 0) {
Glauber Costa 47b075
+	    VNC_DEBUG("Client verification failed\n");
Glauber Costa 47b075
+	    vnc_client_error(vs);
Glauber Costa 47b075
+	    return -1;
Glauber Costa 47b075
+	} else {
Glauber Costa 47b075
+	    VNC_DEBUG("Client verification passed\n");
Glauber Costa 47b075
+	}
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+
Glauber Costa 47b075
+    VNC_DEBUG("Handshake done, switching to TLS data mode\n");
Glauber Costa 47b075
+    vs->tls.wiremode = VNC_WIREMODE_TLS;
Glauber Costa 47b075
+    qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
Glauber Costa 47b075
+
Glauber Costa 47b075
+    start_auth_vencrypt_subauth(vs);
Glauber Costa 47b075
+
Glauber Costa 47b075
+    return 0;
Glauber Costa 47b075
+}
Glauber Costa 47b075
+
Glauber Costa 47b075
+static void vnc_tls_handshake_io(void *opaque) {
Glauber Costa 47b075
+    struct VncState *vs = (struct VncState *)opaque;
Glauber Costa 47b075
+
Glauber Costa 47b075
+    VNC_DEBUG("Handshake IO continue\n");
Glauber Costa 47b075
+    vnc_start_vencrypt_handshake(vs);
Glauber Costa 47b075
+}
Glauber Costa 47b075
+
Glauber Costa 47b075
+
Glauber Costa 47b075
+
Glauber Costa 47b075
+#define NEED_X509_AUTH(vs)			      \
Glauber Costa 47b075
+    ((vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509NONE ||   \
Glauber Costa 47b075
+     (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509VNC ||    \
Glauber Costa 47b075
+     (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509PLAIN)
Glauber Costa 47b075
+
Glauber Costa 47b075
+
Glauber Costa 47b075
+static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len)
Glauber Costa 47b075
+{
Glauber Costa 47b075
+    int auth = read_u32(data, 0);
Glauber Costa 47b075
+
Glauber Costa 47b075
+    if (auth != vs->vd->subauth) {
Glauber Costa 47b075
+	VNC_DEBUG("Rejecting auth %d\n", auth);
Glauber Costa 47b075
+	vnc_write_u8(vs, 0); /* Reject auth */
Glauber Costa 47b075
+	vnc_flush(vs);
Glauber Costa 47b075
+	vnc_client_error(vs);
Glauber Costa 47b075
+    } else {
Glauber Costa 47b075
+	VNC_DEBUG("Accepting auth %d, setting up TLS for handshake\n", auth);
Glauber Costa 47b075
+	vnc_write_u8(vs, 1); /* Accept auth */
Glauber Costa 47b075
+	vnc_flush(vs);
Glauber Costa 47b075
+
Glauber Costa 47b075
+	if (vnc_tls_client_setup(vs, NEED_X509_AUTH(vs)) < 0) {
Glauber Costa 47b075
+	    VNC_DEBUG("Failed to setup TLS\n");
Glauber Costa 47b075
+	    return 0;
Glauber Costa 47b075
+	}
Glauber Costa 47b075
+
Glauber Costa 47b075
+	VNC_DEBUG("Start TLS VeNCrypt handshake process\n");
Glauber Costa 47b075
+	if (vnc_start_vencrypt_handshake(vs) < 0) {
Glauber Costa 47b075
+	    VNC_DEBUG("Failed to start TLS handshake\n");
Glauber Costa 47b075
+	    return 0;
Glauber Costa 47b075
+	}
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+    return 0;
Glauber Costa 47b075
+}
Glauber Costa 47b075
+
Glauber Costa 47b075
+static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len)
Glauber Costa 47b075
+{
Glauber Costa 47b075
+    if (data[0] != 0 ||
Glauber Costa 47b075
+	data[1] != 2) {
Glauber Costa 47b075
+	VNC_DEBUG("Unsupported VeNCrypt protocol %d.%d\n", (int)data[0], (int)data[1]);
Glauber Costa 47b075
+	vnc_write_u8(vs, 1); /* Reject version */
Glauber Costa 47b075
+	vnc_flush(vs);
Glauber Costa 47b075
+	vnc_client_error(vs);
Glauber Costa 47b075
+    } else {
Glauber Costa 47b075
+	VNC_DEBUG("Sending allowed auth %d\n", vs->vd->subauth);
Glauber Costa 47b075
+	vnc_write_u8(vs, 0); /* Accept version */
Glauber Costa 47b075
+	vnc_write_u8(vs, 1); /* Number of sub-auths */
Glauber Costa 47b075
+	vnc_write_u32(vs, vs->vd->subauth); /* The supported auth */
Glauber Costa 47b075
+	vnc_flush(vs);
Glauber Costa 47b075
+	vnc_read_when(vs, protocol_client_vencrypt_auth, 4);
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+    return 0;
Glauber Costa 47b075
+}
Glauber Costa 47b075
+
Glauber Costa 47b075
+
Glauber Costa 47b075
+void start_auth_vencrypt(VncState *vs)
Glauber Costa 47b075
+{
Glauber Costa 47b075
+    /* Send VeNCrypt version 0.2 */
Glauber Costa 47b075
+    vnc_write_u8(vs, 0);
Glauber Costa 47b075
+    vnc_write_u8(vs, 2);
Glauber Costa 47b075
+
Glauber Costa 47b075
+    vnc_read_when(vs, protocol_client_vencrypt_init, 2);
Glauber Costa 47b075
+}
Glauber Costa 47b075
+
Glauber Costa 47b075
Index: qemu-kvm-0.10/qemu/vnc-auth-vencrypt.h
Glauber Costa 47b075
===================================================================
Glauber Costa 47b075
--- /dev/null
Glauber Costa 47b075
+++ qemu-kvm-0.10/qemu/vnc-auth-vencrypt.h
Glauber Costa 47b075
@@ -0,0 +1,33 @@
Glauber Costa 47b075
+/*
Glauber Costa 47b075
+ * QEMU VNC display driver
Glauber Costa 47b075
+ *
Glauber Costa 47b075
+ * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
Glauber Costa 47b075
+ * Copyright (C) 2006 Fabrice Bellard
Glauber Costa 47b075
+ * Copyright (C) 2009 Red Hat, Inc
Glauber Costa 47b075
+ *
Glauber Costa 47b075
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
Glauber Costa 47b075
+ * of this software and associated documentation files (the "Software"), to deal
Glauber Costa 47b075
+ * in the Software without restriction, including without limitation the rights
Glauber Costa 47b075
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
Glauber Costa 47b075
+ * copies of the Software, and to permit persons to whom the Software is
Glauber Costa 47b075
+ * furnished to do so, subject to the following conditions:
Glauber Costa 47b075
+ *
Glauber Costa 47b075
+ * The above copyright notice and this permission notice shall be included in
Glauber Costa 47b075
+ * all copies or substantial portions of the Software.
Glauber Costa 47b075
+ *
Glauber Costa 47b075
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Glauber Costa 47b075
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Glauber Costa 47b075
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
Glauber Costa 47b075
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Glauber Costa 47b075
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Glauber Costa 47b075
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
Glauber Costa 47b075
+ * THE SOFTWARE.
Glauber Costa 47b075
+ */
Glauber Costa 47b075
+
Glauber Costa 47b075
+
Glauber Costa 47b075
+#ifndef __QEMU_VNC_AUTH_VENCRYPT_H__
Glauber Costa 47b075
+#define __QEMU_VNC_AUTH_VENCRYPT_H__
Glauber Costa 47b075
+
Glauber Costa 47b075
+void start_auth_vencrypt(VncState *vs);
Glauber Costa 47b075
+
Glauber Costa 47b075
+#endif /* __QEMU_VNC_AUTH_VENCRYPT_H__ */
Glauber Costa 47b075
Index: qemu-kvm-0.10/qemu/vnc-tls.c
Glauber Costa 47b075
===================================================================
Glauber Costa 47b075
--- /dev/null
Glauber Costa 47b075
+++ qemu-kvm-0.10/qemu/vnc-tls.c
Glauber Costa 47b075
@@ -0,0 +1,414 @@
Glauber Costa 47b075
+/*
Glauber Costa 47b075
+ * QEMU VNC display driver: TLS helpers
Glauber Costa 47b075
+ *
Glauber Costa 47b075
+ * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
Glauber Costa 47b075
+ * Copyright (C) 2006 Fabrice Bellard
Glauber Costa 47b075
+ * Copyright (C) 2009 Red Hat, Inc
Glauber Costa 47b075
+ *
Glauber Costa 47b075
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
Glauber Costa 47b075
+ * of this software and associated documentation files (the "Software"), to deal
Glauber Costa 47b075
+ * in the Software without restriction, including without limitation the rights
Glauber Costa 47b075
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
Glauber Costa 47b075
+ * copies of the Software, and to permit persons to whom the Software is
Glauber Costa 47b075
+ * furnished to do so, subject to the following conditions:
Glauber Costa 47b075
+ *
Glauber Costa 47b075
+ * The above copyright notice and this permission notice shall be included in
Glauber Costa 47b075
+ * all copies or substantial portions of the Software.
Glauber Costa 47b075
+ *
Glauber Costa 47b075
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Glauber Costa 47b075
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Glauber Costa 47b075
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
Glauber Costa 47b075
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Glauber Costa 47b075
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Glauber Costa 47b075
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
Glauber Costa 47b075
+ * THE SOFTWARE.
Glauber Costa 47b075
+ */
Glauber Costa 47b075
+
Glauber Costa 47b075
+#include "vnc.h"
Glauber Costa 47b075
+#include "qemu_socket.h"
Glauber Costa 47b075
+
Glauber Costa 47b075
+#if defined(_VNC_DEBUG) && _VNC_DEBUG >= 2
Glauber Costa 47b075
+/* Very verbose, so only enabled for _VNC_DEBUG >= 2 */
Glauber Costa 47b075
+static void vnc_debug_gnutls_log(int level, const char* str) {
Glauber Costa 47b075
+    VNC_DEBUG("%d %s", level, str);
Glauber Costa 47b075
+}
Glauber Costa 47b075
+#endif /* defined(_VNC_DEBUG) && _VNC_DEBUG >= 2 */
Glauber Costa 47b075
+
Glauber Costa 47b075
+
Glauber Costa 47b075
+#define DH_BITS 1024
Glauber Costa 47b075
+static gnutls_dh_params_t dh_params;
Glauber Costa 47b075
+
Glauber Costa 47b075
+static int vnc_tls_initialize(void)
Glauber Costa 47b075
+{
Glauber Costa 47b075
+    static int tlsinitialized = 0;
Glauber Costa 47b075
+
Glauber Costa 47b075
+    if (tlsinitialized)
Glauber Costa 47b075
+	return 1;
Glauber Costa 47b075
+
Glauber Costa 47b075
+    if (gnutls_global_init () < 0)
Glauber Costa 47b075
+	return 0;
Glauber Costa 47b075
+
Glauber Costa 47b075
+    /* XXX ought to re-generate diffie-hellmen params periodically */
Glauber Costa 47b075
+    if (gnutls_dh_params_init (&dh_params) < 0)
Glauber Costa 47b075
+	return 0;
Glauber Costa 47b075
+    if (gnutls_dh_params_generate2 (dh_params, DH_BITS) < 0)
Glauber Costa 47b075
+	return 0;
Glauber Costa 47b075
+
Glauber Costa 47b075
+#if defined(_VNC_DEBUG) && _VNC_DEBUG >= 2
Glauber Costa 47b075
+    gnutls_global_set_log_level(10);
Glauber Costa 47b075
+    gnutls_global_set_log_function(vnc_debug_gnutls_log);
Glauber Costa 47b075
+#endif
Glauber Costa 47b075
+
Glauber Costa 47b075
+    tlsinitialized = 1;
Glauber Costa 47b075
+
Glauber Costa 47b075
+    return 1;
Glauber Costa 47b075
+}
Glauber Costa 47b075
+
Glauber Costa 47b075
+static ssize_t vnc_tls_push(gnutls_transport_ptr_t transport,
Glauber Costa 47b075
+			    const void *data,
Glauber Costa 47b075
+			    size_t len) {
Glauber Costa 47b075
+    struct VncState *vs = (struct VncState *)transport;
Glauber Costa 47b075
+    int ret;
Glauber Costa 47b075
+
Glauber Costa 47b075
+ retry:
Glauber Costa 47b075
+    ret = send(vs->csock, data, len, 0);
Glauber Costa 47b075
+    if (ret < 0) {
Glauber Costa 47b075
+	if (errno == EINTR)
Glauber Costa 47b075
+	    goto retry;
Glauber Costa 47b075
+	return -1;
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+    return ret;
Glauber Costa 47b075
+}
Glauber Costa 47b075
+
Glauber Costa 47b075
+
Glauber Costa 47b075
+static ssize_t vnc_tls_pull(gnutls_transport_ptr_t transport,
Glauber Costa 47b075
+			    void *data,
Glauber Costa 47b075
+			    size_t len) {
Glauber Costa 47b075
+    struct VncState *vs = (struct VncState *)transport;
Glauber Costa 47b075
+    int ret;
Glauber Costa 47b075
+
Glauber Costa 47b075
+ retry:
Glauber Costa 47b075
+    ret = recv(vs->csock, data, len, 0);
Glauber Costa 47b075
+    if (ret < 0) {
Glauber Costa 47b075
+	if (errno == EINTR)
Glauber Costa 47b075
+	    goto retry;
Glauber Costa 47b075
+	return -1;
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+    return ret;
Glauber Costa 47b075
+}
Glauber Costa 47b075
+
Glauber Costa 47b075
+
Glauber Costa 47b075
+static gnutls_anon_server_credentials vnc_tls_initialize_anon_cred(void)
Glauber Costa 47b075
+{
Glauber Costa 47b075
+    gnutls_anon_server_credentials anon_cred;
Glauber Costa 47b075
+    int ret;
Glauber Costa 47b075
+
Glauber Costa 47b075
+    if ((ret = gnutls_anon_allocate_server_credentials(&anon_cred)) < 0) {
Glauber Costa 47b075
+	VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
Glauber Costa 47b075
+	return NULL;
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+
Glauber Costa 47b075
+    gnutls_anon_set_server_dh_params(anon_cred, dh_params);
Glauber Costa 47b075
+
Glauber Costa 47b075
+    return anon_cred;
Glauber Costa 47b075
+}
Glauber Costa 47b075
+
Glauber Costa 47b075
+
Glauber Costa 47b075
+static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(VncDisplay *vd)
Glauber Costa 47b075
+{
Glauber Costa 47b075
+    gnutls_certificate_credentials_t x509_cred;
Glauber Costa 47b075
+    int ret;
Glauber Costa 47b075
+
Glauber Costa 47b075
+    if (!vd->tls.x509cacert) {
Glauber Costa 47b075
+	VNC_DEBUG("No CA x509 certificate specified\n");
Glauber Costa 47b075
+	return NULL;
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+    if (!vd->tls.x509cert) {
Glauber Costa 47b075
+	VNC_DEBUG("No server x509 certificate specified\n");
Glauber Costa 47b075
+	return NULL;
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+    if (!vd->tls.x509key) {
Glauber Costa 47b075
+	VNC_DEBUG("No server private key specified\n");
Glauber Costa 47b075
+	return NULL;
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+
Glauber Costa 47b075
+    if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) {
Glauber Costa 47b075
+	VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
Glauber Costa 47b075
+	return NULL;
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+    if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred,
Glauber Costa 47b075
+						      vd->tls.x509cacert,
Glauber Costa 47b075
+						      GNUTLS_X509_FMT_PEM)) < 0) {
Glauber Costa 47b075
+	VNC_DEBUG("Cannot load CA certificate %s\n", gnutls_strerror(ret));
Glauber Costa 47b075
+	gnutls_certificate_free_credentials(x509_cred);
Glauber Costa 47b075
+	return NULL;
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+
Glauber Costa 47b075
+    if ((ret = gnutls_certificate_set_x509_key_file (x509_cred,
Glauber Costa 47b075
+						     vd->tls.x509cert,
Glauber Costa 47b075
+						     vd->tls.x509key,
Glauber Costa 47b075
+						     GNUTLS_X509_FMT_PEM)) < 0) {
Glauber Costa 47b075
+	VNC_DEBUG("Cannot load certificate & key %s\n", gnutls_strerror(ret));
Glauber Costa 47b075
+	gnutls_certificate_free_credentials(x509_cred);
Glauber Costa 47b075
+	return NULL;
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+
Glauber Costa 47b075
+    if (vd->tls.x509cacrl) {
Glauber Costa 47b075
+	if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred,
Glauber Costa 47b075
+							vd->tls.x509cacrl,
Glauber Costa 47b075
+							GNUTLS_X509_FMT_PEM)) < 0) {
Glauber Costa 47b075
+	    VNC_DEBUG("Cannot load CRL %s\n", gnutls_strerror(ret));
Glauber Costa 47b075
+	    gnutls_certificate_free_credentials(x509_cred);
Glauber Costa 47b075
+	    return NULL;
Glauber Costa 47b075
+	}
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+
Glauber Costa 47b075
+    gnutls_certificate_set_dh_params (x509_cred, dh_params);
Glauber Costa 47b075
+
Glauber Costa 47b075
+    return x509_cred;
Glauber Costa 47b075
+}
Glauber Costa 47b075
+
Glauber Costa 47b075
+
Glauber Costa 47b075
+int vnc_tls_validate_certificate(struct VncState *vs)
Glauber Costa 47b075
+{
Glauber Costa 47b075
+    int ret;
Glauber Costa 47b075
+    unsigned int status;
Glauber Costa 47b075
+    const gnutls_datum_t *certs;
Glauber Costa 47b075
+    unsigned int nCerts, i;
Glauber Costa 47b075
+    time_t now;
Glauber Costa 47b075
+
Glauber Costa 47b075
+    VNC_DEBUG("Validating client certificate\n");
Glauber Costa 47b075
+    if ((ret = gnutls_certificate_verify_peers2 (vs->tls.session, &status)) < 0) {
Glauber Costa 47b075
+	VNC_DEBUG("Verify failed %s\n", gnutls_strerror(ret));
Glauber Costa 47b075
+	return -1;
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+
Glauber Costa 47b075
+    if ((now = time(NULL)) == ((time_t)-1)) {
Glauber Costa 47b075
+	return -1;
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+
Glauber Costa 47b075
+    if (status != 0) {
Glauber Costa 47b075
+	if (status & GNUTLS_CERT_INVALID)
Glauber Costa 47b075
+	    VNC_DEBUG("The certificate is not trusted.\n");
Glauber Costa 47b075
+
Glauber Costa 47b075
+	if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
Glauber Costa 47b075
+	    VNC_DEBUG("The certificate hasn't got a known issuer.\n");
Glauber Costa 47b075
+
Glauber Costa 47b075
+	if (status & GNUTLS_CERT_REVOKED)
Glauber Costa 47b075
+	    VNC_DEBUG("The certificate has been revoked.\n");
Glauber Costa 47b075
+
Glauber Costa 47b075
+	if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
Glauber Costa 47b075
+	    VNC_DEBUG("The certificate uses an insecure algorithm\n");
Glauber Costa 47b075
+
Glauber Costa 47b075
+	return -1;
Glauber Costa 47b075
+    } else {
Glauber Costa 47b075
+	VNC_DEBUG("Certificate is valid!\n");
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+
Glauber Costa 47b075
+    /* Only support x509 for now */
Glauber Costa 47b075
+    if (gnutls_certificate_type_get(vs->tls.session) != GNUTLS_CRT_X509)
Glauber Costa 47b075
+	return -1;
Glauber Costa 47b075
+
Glauber Costa 47b075
+    if (!(certs = gnutls_certificate_get_peers(vs->tls.session, &nCerts)))
Glauber Costa 47b075
+	return -1;
Glauber Costa 47b075
+
Glauber Costa 47b075
+    for (i = 0 ; i < nCerts ; i++) {
Glauber Costa 47b075
+	gnutls_x509_crt_t cert;
Glauber Costa 47b075
+	VNC_DEBUG ("Checking certificate chain %d\n", i);
Glauber Costa 47b075
+	if (gnutls_x509_crt_init (&cert) < 0)
Glauber Costa 47b075
+	    return -1;
Glauber Costa 47b075
+
Glauber Costa 47b075
+	if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) {
Glauber Costa 47b075
+	    gnutls_x509_crt_deinit (cert);
Glauber Costa 47b075
+	    return -1;
Glauber Costa 47b075
+	}
Glauber Costa 47b075
+
Glauber Costa 47b075
+	if (gnutls_x509_crt_get_expiration_time (cert) < now) {
Glauber Costa 47b075
+	    VNC_DEBUG("The certificate has expired\n");
Glauber Costa 47b075
+	    gnutls_x509_crt_deinit (cert);
Glauber Costa 47b075
+	    return -1;
Glauber Costa 47b075
+	}
Glauber Costa 47b075
+
Glauber Costa 47b075
+	if (gnutls_x509_crt_get_activation_time (cert) > now) {
Glauber Costa 47b075
+	    VNC_DEBUG("The certificate is not yet activated\n");
Glauber Costa 47b075
+	    gnutls_x509_crt_deinit (cert);
Glauber Costa 47b075
+	    return -1;
Glauber Costa 47b075
+	}
Glauber Costa 47b075
+
Glauber Costa 47b075
+	if (gnutls_x509_crt_get_activation_time (cert) > now) {
Glauber Costa 47b075
+	    VNC_DEBUG("The certificate is not yet activated\n");
Glauber Costa 47b075
+	    gnutls_x509_crt_deinit (cert);
Glauber Costa 47b075
+	    return -1;
Glauber Costa 47b075
+	}
Glauber Costa 47b075
+
Glauber Costa 47b075
+	gnutls_x509_crt_deinit (cert);
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+
Glauber Costa 47b075
+    return 0;
Glauber Costa 47b075
+}
Glauber Costa 47b075
+
Glauber Costa 47b075
+
Glauber Costa 47b075
+int vnc_tls_client_setup(struct VncState *vs,
Glauber Costa 47b075
+			 int needX509Creds) {
Glauber Costa 47b075
+    static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
Glauber Costa 47b075
+    static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 };
Glauber Costa 47b075
+    static const int kx_anon[] = {GNUTLS_KX_ANON_DH, 0};
Glauber Costa 47b075
+    static const int kx_x509[] = {GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0};
Glauber Costa 47b075
+
Glauber Costa 47b075
+    VNC_DEBUG("Do TLS setup\n");
Glauber Costa 47b075
+    if (vnc_tls_initialize() < 0) {
Glauber Costa 47b075
+	VNC_DEBUG("Failed to init TLS\n");
Glauber Costa 47b075
+	vnc_client_error(vs);
Glauber Costa 47b075
+	return -1;
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+    if (vs->tls.session == NULL) {
Glauber Costa 47b075
+	if (gnutls_init(&vs->tls.session, GNUTLS_SERVER) < 0) {
Glauber Costa 47b075
+	    vnc_client_error(vs);
Glauber Costa 47b075
+	    return -1;
Glauber Costa 47b075
+	}
Glauber Costa 47b075
+
Glauber Costa 47b075
+	if (gnutls_set_default_priority(vs->tls.session) < 0) {
Glauber Costa 47b075
+	    gnutls_deinit(vs->tls.session);
Glauber Costa 47b075
+	    vs->tls.session = NULL;
Glauber Costa 47b075
+	    vnc_client_error(vs);
Glauber Costa 47b075
+	    return -1;
Glauber Costa 47b075
+	}
Glauber Costa 47b075
+
Glauber Costa 47b075
+	if (gnutls_kx_set_priority(vs->tls.session, needX509Creds ? kx_x509 : kx_anon) < 0) {
Glauber Costa 47b075
+	    gnutls_deinit(vs->tls.session);
Glauber Costa 47b075
+	    vs->tls.session = NULL;
Glauber Costa 47b075
+	    vnc_client_error(vs);
Glauber Costa 47b075
+	    return -1;
Glauber Costa 47b075
+	}
Glauber Costa 47b075
+
Glauber Costa 47b075
+	if (gnutls_certificate_type_set_priority(vs->tls.session, cert_type_priority) < 0) {
Glauber Costa 47b075
+	    gnutls_deinit(vs->tls.session);
Glauber Costa 47b075
+	    vs->tls.session = NULL;
Glauber Costa 47b075
+	    vnc_client_error(vs);
Glauber Costa 47b075
+	    return -1;
Glauber Costa 47b075
+	}
Glauber Costa 47b075
+
Glauber Costa 47b075
+	if (gnutls_protocol_set_priority(vs->tls.session, protocol_priority) < 0) {
Glauber Costa 47b075
+	    gnutls_deinit(vs->tls.session);
Glauber Costa 47b075
+	    vs->tls.session = NULL;
Glauber Costa 47b075
+	    vnc_client_error(vs);
Glauber Costa 47b075
+	    return -1;
Glauber Costa 47b075
+	}
Glauber Costa 47b075
+
Glauber Costa 47b075
+	if (needX509Creds) {
Glauber Costa 47b075
+	    gnutls_certificate_server_credentials x509_cred = vnc_tls_initialize_x509_cred(vs->vd);
Glauber Costa 47b075
+	    if (!x509_cred) {
Glauber Costa 47b075
+		gnutls_deinit(vs->tls.session);
Glauber Costa 47b075
+		vs->tls.session = NULL;
Glauber Costa 47b075
+		vnc_client_error(vs);
Glauber Costa 47b075
+		return -1;
Glauber Costa 47b075
+	    }
Glauber Costa 47b075
+	    if (gnutls_credentials_set(vs->tls.session, GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) {
Glauber Costa 47b075
+		gnutls_deinit(vs->tls.session);
Glauber Costa 47b075
+		vs->tls.session = NULL;
Glauber Costa 47b075
+		gnutls_certificate_free_credentials(x509_cred);
Glauber Costa 47b075
+		vnc_client_error(vs);
Glauber Costa 47b075
+		return -1;
Glauber Costa 47b075
+	    }
Glauber Costa 47b075
+	    if (vs->vd->tls.x509verify) {
Glauber Costa 47b075
+		VNC_DEBUG("Requesting a client certificate\n");
Glauber Costa 47b075
+		gnutls_certificate_server_set_request (vs->tls.session, GNUTLS_CERT_REQUEST);
Glauber Costa 47b075
+	    }
Glauber Costa 47b075
+
Glauber Costa 47b075
+	} else {
Glauber Costa 47b075
+	    gnutls_anon_server_credentials anon_cred = vnc_tls_initialize_anon_cred();
Glauber Costa 47b075
+	    if (!anon_cred) {
Glauber Costa 47b075
+		gnutls_deinit(vs->tls.session);
Glauber Costa 47b075
+		vs->tls.session = NULL;
Glauber Costa 47b075
+		vnc_client_error(vs);
Glauber Costa 47b075
+		return -1;
Glauber Costa 47b075
+	    }
Glauber Costa 47b075
+	    if (gnutls_credentials_set(vs->tls.session, GNUTLS_CRD_ANON, anon_cred) < 0) {
Glauber Costa 47b075
+		gnutls_deinit(vs->tls.session);
Glauber Costa 47b075
+		vs->tls.session = NULL;
Glauber Costa 47b075
+		gnutls_anon_free_server_credentials(anon_cred);
Glauber Costa 47b075
+		vnc_client_error(vs);
Glauber Costa 47b075
+		return -1;
Glauber Costa 47b075
+	    }
Glauber Costa 47b075
+	}
Glauber Costa 47b075
+
Glauber Costa 47b075
+	gnutls_transport_set_ptr(vs->tls.session, (gnutls_transport_ptr_t)vs);
Glauber Costa 47b075
+	gnutls_transport_set_push_function(vs->tls.session, vnc_tls_push);
Glauber Costa 47b075
+	gnutls_transport_set_pull_function(vs->tls.session, vnc_tls_pull);
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+    return 0;
Glauber Costa 47b075
+}
Glauber Costa 47b075
+
Glauber Costa 47b075
+
Glauber Costa 47b075
+void vnc_tls_client_cleanup(struct VncState *vs)
Glauber Costa 47b075
+{
Glauber Costa 47b075
+    if (vs->tls.session) {
Glauber Costa 47b075
+	gnutls_deinit(vs->tls.session);
Glauber Costa 47b075
+	vs->tls.session = NULL;
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+    vs->tls.wiremode = VNC_WIREMODE_CLEAR;
Glauber Costa 47b075
+}
Glauber Costa 47b075
+
Glauber Costa 47b075
+
Glauber Costa 47b075
+
Glauber Costa 47b075
+static int vnc_set_x509_credential(VncDisplay *vd,
Glauber Costa 47b075
+				   const char *certdir,
Glauber Costa 47b075
+				   const char *filename,
Glauber Costa 47b075
+				   char **cred,
Glauber Costa 47b075
+				   int ignoreMissing)
Glauber Costa 47b075
+{
Glauber Costa 47b075
+    struct stat sb;
Glauber Costa 47b075
+
Glauber Costa 47b075
+    if (*cred) {
Glauber Costa 47b075
+	qemu_free(*cred);
Glauber Costa 47b075
+	*cred = NULL;
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+
Glauber Costa 47b075
+    *cred = qemu_malloc(strlen(certdir) + strlen(filename) + 2);
Glauber Costa 47b075
+
Glauber Costa 47b075
+    strcpy(*cred, certdir);
Glauber Costa 47b075
+    strcat(*cred, "/");
Glauber Costa 47b075
+    strcat(*cred, filename);
Glauber Costa 47b075
+
Glauber Costa 47b075
+    VNC_DEBUG("Check %s\n", *cred);
Glauber Costa 47b075
+    if (stat(*cred, &sb) < 0) {
Glauber Costa 47b075
+	qemu_free(*cred);
Glauber Costa 47b075
+	*cred = NULL;
Glauber Costa 47b075
+	if (ignoreMissing && errno == ENOENT)
Glauber Costa 47b075
+	    return 0;
Glauber Costa 47b075
+	return -1;
Glauber Costa 47b075
+    }
Glauber Costa 47b075
+
Glauber Costa 47b075
+    return 0;
Glauber Costa 47b075
+}
Glauber Costa 47b075
+
Glauber Costa 47b075
+
Glauber Costa 47b075
+#define X509_CA_CERT_FILE "ca-cert.pem"
Glauber Costa 47b075
+#define X509_CA_CRL_FILE "ca-crl.pem"
Glauber Costa 47b075
+#define X509_SERVER_KEY_FILE "server-key.pem"
Glauber Costa 47b075
+#define X509_SERVER_CERT_FILE "server-cert.pem"
Glauber Costa 47b075
+
Glauber Costa 47b075
+
Glauber Costa 47b075
+int vnc_tls_set_x509_creds_dir(VncDisplay *vd,
Glauber Costa 47b075
+			       const char *certdir)
Glauber Costa 47b075
+{
Glauber Costa 47b075
+    if (vnc_set_x509_credential(vd, certdir, X509_CA_CERT_FILE, &vd->tls.x509cacert, 0) < 0)
Glauber Costa 47b075
+	goto cleanup;
Glauber Costa 47b075
+    if (vnc_set_x509_credential(vd, certdir, X509_CA_CRL_FILE, &vd->tls.x509cacrl, 1) < 0)
Glauber Costa 47b075
+	goto cleanup;
Glauber Costa 47b075
+    if (vnc_set_x509_credential(vd, certdir, X509_SERVER_CERT_FILE, &vd->tls.x509cert, 0) < 0)
Glauber Costa 47b075
+	goto cleanup;
Glauber Costa 47b075
+    if (vnc_set_x509_credential(vd, certdir, X509_SERVER_KEY_FILE, &vd->tls.x509key, 0) < 0)
Glauber Costa 47b075
+	goto cleanup;
Glauber Costa 47b075
+
Glauber Costa 47b075
+    return 0;
Glauber Costa 47b075
+
Glauber Costa 47b075
+ cleanup:
Glauber Costa 47b075
+    qemu_free(vd->tls.x509cacert);
Glauber Costa 47b075
+    qemu_free(vd->tls.x509cacrl);
Glauber Costa 47b075
+    qemu_free(vd->tls.x509cert);
Glauber Costa 47b075
+    qemu_free(vd->tls.x509key);
Glauber Costa 47b075
+    vd->tls.x509cacert = vd->tls.x509cacrl = vd->tls.x509cert = vd->tls.x509key = NULL;
Glauber Costa 47b075
+    return -1;
Glauber Costa 47b075
+}
Glauber Costa 47b075
+
Glauber Costa 47b075
Index: qemu-kvm-0.10/qemu/vnc-tls.h
Glauber Costa 47b075
===================================================================
Glauber Costa 47b075
--- /dev/null
Glauber Costa 47b075
+++ qemu-kvm-0.10/qemu/vnc-tls.h
Glauber Costa 47b075
@@ -0,0 +1,70 @@
Glauber Costa 47b075
+/*
Glauber Costa 47b075
+ * QEMU VNC display driver. TLS helpers
Glauber Costa 47b075
+ *
Glauber Costa 47b075
+ * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
Glauber Costa 47b075
+ * Copyright (C) 2006 Fabrice Bellard
Glauber Costa 47b075
+ * Copyright (C) 2009 Red Hat, Inc
Glauber Costa 47b075
+ *
Glauber Costa 47b075
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
Glauber Costa 47b075
+ * of this software and associated documentation files (the "Software"), to deal
Glauber Costa 47b075
+ * in the Software without restriction, including without limitation the rights
Glauber Costa 47b075
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
Glauber Costa 47b075
+ * copies of the Software, and to permit persons to whom the Software is
Glauber Costa 47b075
+ * furnished to do so, subject to the following conditions:
Glauber Costa 47b075
+ *
Glauber Costa 47b075
+ * The above copyright notice and this permission notice shall be included in
Glauber Costa 47b075
+ * all copies or substantial portions of the Software.
Glauber Costa 47b075
+ *
Glauber Costa 47b075
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Glauber Costa 47b075
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Glauber Costa 47b075
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
Glauber Costa 47b075
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Glauber Costa 47b075
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Glauber Costa 47b075
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
Glauber Costa 47b075
+ * THE SOFTWARE.
Glauber Costa 47b075
+ */
Glauber Costa 47b075
+
Glauber Costa 47b075
+
Glauber Costa 47b075
+#ifndef __QEMU_VNC_TLS_H__
Glauber Costa 47b075
+#define __QEMU_VNC_TLS_H__
Glauber Costa 47b075
+
Glauber Costa 47b075
+#include <gnutls/gnutls.h>
Glauber Costa 47b075
+#include <gnutls/x509.h>
Glauber Costa 47b075
+
Glauber Costa 47b075
+enum {
Glauber Costa 47b075
+    VNC_WIREMODE_CLEAR,
Glauber Costa 47b075
+    VNC_WIREMODE_TLS,
Glauber Costa 47b075
+};
Glauber Costa 47b075
+
Glauber Costa 47b075
+typedef struct VncDisplayTLS VncDisplayTLS;
Glauber Costa 47b075
+typedef struct VncStateTLS VncStateTLS;
Glauber Costa 47b075
+
Glauber Costa 47b075
+/* Server state */
Glauber Costa 47b075
+struct VncDisplayTLS {
Glauber Costa 47b075
+    int x509verify; /* Non-zero if server requests & validates client cert */
Glauber Costa 47b075
+
Glauber Costa 47b075
+    /* Paths to x509 certs/keys */
Glauber Costa 47b075
+    char *x509cacert;
Glauber Costa 47b075
+    char *x509cacrl;
Glauber Costa 47b075
+    char *x509cert;
Glauber Costa 47b075
+    char *x509key;
Glauber Costa 47b075
+};
Glauber Costa 47b075
+
Glauber Costa 47b075
+/* Per client state */
Glauber Costa 47b075
+struct VncStateTLS {
Glauber Costa 47b075
+    /* Whether data is being TLS encrypted yet */
Glauber Costa 47b075
+    int wiremode;
Glauber Costa 47b075
+    gnutls_session_t session;
Glauber Costa 47b075
+};
Glauber Costa 47b075
+
Glauber Costa 47b075
+int vnc_tls_client_setup(VncState *vs, int x509Creds);
Glauber Costa 47b075
+void vnc_tls_client_cleanup(VncState *vs);
Glauber Costa 47b075
+
Glauber Costa 47b075
+int vnc_tls_validate_certificate(VncState *vs);
Glauber Costa 47b075
+
Glauber Costa 47b075
+int vnc_tls_set_x509_creds_dir(VncDisplay *vd,
Glauber Costa 47b075
+			       const char *path);
Glauber Costa 47b075
+
Glauber Costa 47b075
+
Glauber Costa 47b075
+#endif /* __QEMU_VNC_TLS_H__ */
Glauber Costa 47b075
+
Glauber Costa 47b075
Index: qemu-kvm-0.10/qemu/vnc.c
Glauber Costa 47b075
===================================================================
Glauber Costa 47b075
--- qemu-kvm-0.10.orig/qemu/vnc.c
Glauber Costa 47b075
+++ qemu-kvm-0.10/qemu/vnc.c
Glauber Costa 47b075
@@ -34,21 +34,6 @@
Glauber Costa 47b075
 #include "vnc_keysym.h"
Glauber Costa 47b075
 #include "d3des.h"
Glauber Costa 47b075
 
Glauber Costa 47b075
-// #define _VNC_DEBUG 1
Glauber Costa 47b075
-
Glauber Costa 47b075
-#ifdef _VNC_DEBUG
Glauber Costa 47b075
-#define VNC_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
Glauber Costa 47b075
-
Glauber Costa 47b075
-#if defined(CONFIG_VNC_TLS) && _VNC_DEBUG >= 2
Glauber Costa 47b075
-/* Very verbose, so only enabled for _VNC_DEBUG >= 2 */
Glauber Costa 47b075
-static void vnc_debug_gnutls_log(int level, const char* str) {
Glauber Costa 47b075
-    VNC_DEBUG("%d %s", level, str);
Glauber Costa 47b075
-}
Glauber Costa 47b075
-#endif /* CONFIG_VNC_TLS && _VNC_DEBUG */
Glauber Costa 47b075
-#else
Glauber Costa 47b075
-#define VNC_DEBUG(fmt, ...) do { } while (0)
Glauber Costa 47b075
-#endif
Glauber Costa 47b075
-
Glauber Costa 47b075
 #define count_bits(c, v) { \
Glauber Costa 47b075
     for (c = 0; v; v >>= 1) \
Glauber Costa 47b075
     { \
Glauber Costa 47b075
@@ -204,14 +189,7 @@ static inline uint32_t vnc_has_feature(V
Glauber Costa 47b075
    3) resolutions > 1024
Glauber Costa 47b075
 */
Glauber Costa 47b075
 
Glauber Costa 47b075
-static void vnc_write(VncState *vs, const void *data, size_t len);
Glauber Costa 47b075
-static void vnc_write_u32(VncState *vs, uint32_t value);
Glauber Costa 47b075
-static void vnc_write_s32(VncState *vs, int32_t value);
Glauber Costa 47b075
-static void vnc_write_u16(VncState *vs, uint16_t value);
Glauber Costa 47b075
-static void vnc_write_u8(VncState *vs, uint8_t value);
Glauber Costa 47b075
-static void vnc_flush(VncState *vs);
Glauber Costa 47b075
 static void vnc_update_client(void *opaque);
Glauber Costa 47b075
-static void vnc_client_read(void *opaque);
Glauber Costa 47b075
 
Glauber Costa 47b075
 static void vnc_colordepth(VncState *vs);
Glauber Costa 47b075
 
Glauber Costa 47b075
@@ -867,10 +845,7 @@ static int vnc_client_io_error(VncState 
Glauber Costa 47b075
         if (vs->input.buffer) qemu_free(vs->input.buffer);
Glauber Costa 47b075
         if (vs->output.buffer) qemu_free(vs->output.buffer);
Glauber Costa 47b075
 #ifdef CONFIG_VNC_TLS
Glauber Costa 47b075
-	if (vs->tls_session) {
Glauber Costa 47b075
-	    gnutls_deinit(vs->tls_session);
Glauber Costa 47b075
-	    vs->tls_session = NULL;
Glauber Costa 47b075
-	}
Glauber Costa 47b075
+	vnc_tls_client_cleanup(vs);
Glauber Costa 47b075
 #endif /* CONFIG_VNC_TLS */
Glauber Costa 47b075
         audio_del(vs);
Glauber Costa 47b075
 
Glauber Costa 47b075
@@ -896,19 +871,20 @@ static int vnc_client_io_error(VncState 
Glauber Costa 47b075
     return ret;
Glauber Costa 47b075
 }
Glauber Costa 47b075
 
Glauber Costa 47b075
-static void vnc_client_error(VncState *vs)
Glauber Costa 47b075
+
Glauber Costa 47b075
+void vnc_client_error(VncState *vs)
Glauber Costa 47b075
 {
Glauber Costa 47b075
     vnc_client_io_error(vs, -1, EINVAL);
Glauber Costa 47b075
 }
Glauber Costa 47b075
 
Glauber Costa 47b075
-static void vnc_client_write(void *opaque)
Glauber Costa 47b075
+void vnc_client_write(void *opaque)
Glauber Costa 47b075
 {
Glauber Costa 47b075
     long ret;
Glauber Costa 47b075
     VncState *vs = opaque;
Glauber Costa 47b075
 
Glauber Costa 47b075
 #ifdef CONFIG_VNC_TLS
Glauber Costa 47b075
-    if (vs->tls_session) {
Glauber Costa 47b075
-	ret = gnutls_write(vs->tls_session, vs->output.buffer, vs->output.offset);
Glauber Costa 47b075
+    if (vs->tls.session) {
Glauber Costa 47b075
+	ret = gnutls_write(vs->tls.session, vs->output.buffer, vs->output.offset);
Glauber Costa 47b075
 	if (ret < 0) {
Glauber Costa 47b075
 	    if (ret == GNUTLS_E_AGAIN)
Glauber Costa 47b075
 		errno = EAGAIN;
Glauber Costa 47b075
@@ -931,13 +907,13 @@ static void vnc_client_write(void *opaqu
Glauber Costa 47b075
     }
Glauber Costa 47b075
 }
Glauber Costa 47b075
 
Glauber Costa 47b075
-static void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
Glauber Costa 47b075
+void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
Glauber Costa 47b075
 {
Glauber Costa 47b075
     vs->read_handler = func;
Glauber Costa 47b075
     vs->read_handler_expect = expecting;
Glauber Costa 47b075
 }
Glauber Costa 47b075
 
Glauber Costa 47b075
-static void vnc_client_read(void *opaque)
Glauber Costa 47b075
+void vnc_client_read(void *opaque)
Glauber Costa 47b075
 {
Glauber Costa 47b075
     VncState *vs = opaque;
Glauber Costa 47b075
     long ret;
Glauber Costa 47b075
@@ -945,8 +921,8 @@ static void vnc_client_read(void *opaque
Glauber Costa 47b075
     buffer_reserve(&vs->input, 4096);
Glauber Costa 47b075
 
Glauber Costa 47b075
 #ifdef CONFIG_VNC_TLS
Glauber Costa 47b075
-    if (vs->tls_session) {
Glauber Costa 47b075
-	ret = gnutls_read(vs->tls_session, buffer_end(&vs->input), 4096);
Glauber Costa 47b075
+    if (vs->tls.session) {
Glauber Costa 47b075
+	ret = gnutls_read(vs->tls.session, buffer_end(&vs->input), 4096);
Glauber Costa 47b075
 	if (ret < 0) {
Glauber Costa 47b075
 	    if (ret == GNUTLS_E_AGAIN)
Glauber Costa 47b075
 		errno = EAGAIN;
Glauber Costa 47b075
@@ -980,7 +956,7 @@ static void vnc_client_read(void *opaque
Glauber Costa 47b075
     }
Glauber Costa 47b075
 }
Glauber Costa 47b075
 
Glauber Costa 47b075
-static void vnc_write(VncState *vs, const void *data, size_t len)
Glauber Costa 47b075
+void vnc_write(VncState *vs, const void *data, size_t len)
Glauber Costa 47b075
 {
Glauber Costa 47b075
     buffer_reserve(&vs->output, len);
Glauber Costa 47b075
 
Glauber Costa 47b075
@@ -991,12 +967,12 @@ static void vnc_write(VncState *vs, cons
Glauber Costa 47b075
     buffer_append(&vs->output, data, len);
Glauber Costa 47b075
 }
Glauber Costa 47b075
 
Glauber Costa 47b075
-static void vnc_write_s32(VncState *vs, int32_t value)
Glauber Costa 47b075
+void vnc_write_s32(VncState *vs, int32_t value)
Glauber Costa 47b075
 {
Glauber Costa 47b075
     vnc_write_u32(vs, *(uint32_t *)&value);
Glauber Costa 47b075
 }
Glauber Costa 47b075
 
Glauber Costa 47b075
-static void vnc_write_u32(VncState *vs, uint32_t value)
Glauber Costa 47b075
+void vnc_write_u32(VncState *vs, uint32_t value)
Glauber Costa 47b075
 {
Glauber Costa 47b075
     uint8_t buf[4];
Glauber Costa 47b075
 
Glauber Costa 47b075
@@ -1008,7 +984,7 @@ static void vnc_write_u32(VncState *vs, 
Glauber Costa 47b075
     vnc_write(vs, buf, 4);
Glauber Costa 47b075
 }
Glauber Costa 47b075
 
Glauber Costa 47b075
-static void vnc_write_u16(VncState *vs, uint16_t value)
Glauber Costa 47b075
+void vnc_write_u16(VncState *vs, uint16_t value)
Glauber Costa 47b075
 {
Glauber Costa 47b075
     uint8_t buf[2];
Glauber Costa 47b075
 
Glauber Costa 47b075
@@ -1018,74 +994,39 @@ static void vnc_write_u16(VncState *vs, 
Glauber Costa 47b075
     vnc_write(vs, buf, 2);
Glauber Costa 47b075
 }
Glauber Costa 47b075
 
Glauber Costa 47b075
-static void vnc_write_u8(VncState *vs, uint8_t value)
Glauber Costa 47b075
+void vnc_write_u8(VncState *vs, uint8_t value)
Glauber Costa 47b075
 {
Glauber Costa 47b075
     vnc_write(vs, (char *)&value, 1);
Glauber Costa 47b075
 }
Glauber Costa 47b075
 
Glauber Costa 47b075
-static void vnc_flush(VncState *vs)
Glauber Costa 47b075
+void vnc_flush(VncState *vs)
Glauber Costa 47b075
 {
Glauber Costa 47b075
     if (vs->output.offset)
Glauber Costa 47b075
 	vnc_client_write(vs);
Glauber Costa 47b075
 }
Glauber Costa 47b075
 
Glauber Costa 47b075
-static uint8_t read_u8(uint8_t *data, size_t offset)
Glauber Costa 47b075
+uint8_t read_u8(uint8_t *data, size_t offset)
Glauber Costa 47b075
 {
Glauber Costa 47b075
     return data[offset];
Glauber Costa 47b075
 }
Glauber Costa 47b075
 
Glauber Costa 47b075
-static uint16_t read_u16(uint8_t *data, size_t offset)
Glauber Costa 47b075
+uint16_t read_u16(uint8_t *data, size_t offset)
Glauber Costa 47b075
 {
Glauber Costa 47b075
     return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF);
Glauber Costa 47b075
 }
Glauber Costa 47b075
 
Glauber Costa 47b075
-static int32_t read_s32(uint8_t *data, size_t offset)
Glauber Costa 47b075
+int32_t read_s32(uint8_t *data, size_t offset)
Glauber Costa 47b075
 {
Glauber Costa 47b075
     return (int32_t)((data[offset] << 24) | (data[offset + 1] << 16) |
Glauber Costa 47b075
 		     (data[offset + 2] << 8) | data[offset + 3]);
Glauber Costa 47b075
 }
Glauber Costa 47b075
 
Glauber Costa 47b075
-static uint32_t read_u32(uint8_t *data, size_t offset)
Glauber Costa 47b075
+uint32_t read_u32(uint8_t *data, size_t offset)
Glauber Costa 47b075
 {
Glauber Costa 47b075
     return ((data[offset] << 24) | (data[offset + 1] << 16) |
Glauber Costa 47b075
 	    (data[offset + 2] << 8) | data[offset + 3]);
Glauber Costa 47b075
 }
Glauber Costa 47b075
 
Glauber Costa 47b075
-#ifdef CONFIG_VNC_TLS
Glauber Costa 47b075
-static ssize_t vnc_tls_push(gnutls_transport_ptr_t transport,
Glauber Costa 47b075
-                            const void *data,
Glauber Costa 47b075
-                            size_t len) {
Glauber Costa 47b075
-    struct VncState *vs = (struct VncState *)transport;
Glauber Costa 47b075
-    int ret;
Glauber Costa 47b075
-
Glauber Costa 47b075
- retry:
Glauber Costa 47b075
-    ret = send(vs->csock, data, len, 0);
Glauber Costa 47b075
-    if (ret < 0) {
Glauber Costa 47b075
-	if (errno == EINTR)
Glauber Costa 47b075
-	    goto retry;
Glauber Costa 47b075
-	return -1;
Glauber Costa 47b075
-    }
Glauber Costa 47b075
-    return ret;
Glauber Costa 47b075
-}
Glauber Costa 47b075
-
Glauber Costa 47b075
-
Glauber Costa 47b075
-static ssize_t vnc_tls_pull(gnutls_transport_ptr_t transport,
Glauber Costa 47b075
-                            void *data,
Glauber Costa 47b075
-                            size_t len) {
Glauber Costa 47b075
-    struct VncState *vs = (struct VncState *)transport;
Glauber Costa 47b075
-    int ret;
Glauber Costa 47b075
-
Glauber Costa 47b075
- retry:
Glauber Costa 47b075
-    ret = recv(vs->csock, data, len, 0);
Glauber Costa 47b075
-    if (ret < 0) {
Glauber Costa 47b075
-	if (errno == EINTR)
Glauber Costa 47b075
-	    goto retry;
Glauber Costa 47b075
-	return -1;
Glauber Costa 47b075
-    }
Glauber Costa 47b075
-    return ret;
Glauber Costa 47b075
-}
Glauber Costa 47b075
-#endif /* CONFIG_VNC_TLS */
Glauber Costa 47b075
-
Glauber Costa 47b075
 static void client_cut_text(VncState *vs, size_t len, uint8_t *text)
Glauber Costa 47b075
 {
Glauber Costa 47b075
 }
Glauber Costa 47b075
@@ -1668,6 +1609,11 @@ static int protocol_client_init(VncState
Glauber Costa 47b075
     return 0;
Glauber Costa 47b075
 }
Glauber Costa 47b075
 
Glauber Costa 47b075
+void start_client_init(VncState *vs)
Glauber Costa 47b075
+{
Glauber Costa 47b075
+    vnc_read_when(vs, protocol_client_init, 1);
Glauber Costa 47b075
+}
Glauber Costa 47b075
+
Glauber Costa 47b075
 static void make_challenge(VncState *vs)
Glauber Costa 47b075
 {
Glauber Costa 47b075
     int i;
Glauber Costa 47b075
@@ -1723,12 +1669,12 @@ static int protocol_client_auth_vnc(VncS
Glauber Costa 47b075
 	vnc_write_u32(vs, 0); /* Accept auth */
Glauber Costa 47b075
 	vnc_flush(vs);
Glauber Costa 47b075
 
Glauber Costa 47b075
-	vnc_read_when(vs, protocol_client_init, 1);
Glauber Costa 47b075
+        start_client_init(vs);
Glauber Costa 47b075
     }
Glauber Costa 47b075
     return 0;
Glauber Costa 47b075
 }
Glauber Costa 47b075
 
Glauber Costa 47b075
-static int start_auth_vnc(VncState *vs)
Glauber Costa 47b075
+void start_auth_vnc(VncState *vs)
Glauber Costa 47b075
 {
Glauber Costa 47b075
     make_challenge(vs);
Glauber Costa 47b075
     /* Send client a 'random' challenge */
Glauber Costa 47b075
@@ -1736,411 +1682,9 @@ static int start_auth_vnc(VncState *vs)
Glauber Costa 47b075
     vnc_flush(vs);
Glauber Costa 47b075
 
Glauber Costa 47b075
     vnc_read_when(vs, protocol_client_auth_vnc, sizeof(vs->challenge));
Glauber Costa 47b075
-    return 0;
Glauber Costa 47b075
-}
Glauber Costa 47b075
-
Glauber Costa 47b075
-
Glauber Costa 47b075
-#ifdef CONFIG_VNC_TLS
Glauber Costa 47b075
-#define DH_BITS 1024
Glauber Costa 47b075
-static gnutls_dh_params_t dh_params;
Glauber Costa 47b075
-
Glauber Costa 47b075
-static int vnc_tls_initialize(void)
Glauber Costa 47b075
-{
Glauber Costa 47b075
-    static int tlsinitialized = 0;
Glauber Costa 47b075
-
Glauber Costa 47b075
-    if (tlsinitialized)
Glauber Costa 47b075
-	return 1;
Glauber Costa 47b075
-
Glauber Costa 47b075
-    if (gnutls_global_init () < 0)
Glauber Costa 47b075
-	return 0;
Glauber Costa 47b075
-
Glauber Costa 47b075
-    /* XXX ought to re-generate diffie-hellmen params periodically */
Glauber Costa 47b075
-    if (gnutls_dh_params_init (&dh_params) < 0)
Glauber Costa 47b075
-	return 0;
Glauber Costa 47b075
-    if (gnutls_dh_params_generate2 (dh_params, DH_BITS) < 0)
Glauber Costa 47b075
-	return 0;
Glauber Costa 47b075
-
Glauber Costa 47b075
-#if defined(_VNC_DEBUG) && _VNC_DEBUG >= 2
Glauber Costa 47b075
-    gnutls_global_set_log_level(10);
Glauber Costa 47b075
-    gnutls_global_set_log_function(vnc_debug_gnutls_log);
Glauber Costa 47b075
-#endif
Glauber Costa 47b075
-
Glauber Costa 47b075
-    tlsinitialized = 1;
Glauber Costa 47b075
-
Glauber Costa 47b075
-    return 1;
Glauber Costa 47b075
-}
Glauber Costa 47b075
-
Glauber Costa 47b075
-static gnutls_anon_server_credentials vnc_tls_initialize_anon_cred(void)
Glauber Costa 47b075
-{
Glauber Costa 47b075
-    gnutls_anon_server_credentials anon_cred;
Glauber Costa 47b075
-    int ret;
Glauber Costa 47b075
-
Glauber Costa 47b075
-    if ((ret = gnutls_anon_allocate_server_credentials(&anon_cred)) < 0) {
Glauber Costa 47b075
-	VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
Glauber Costa 47b075
-	return NULL;
Glauber Costa 47b075
-    }
Glauber Costa 47b075
-
Glauber Costa 47b075
-    gnutls_anon_set_server_dh_params(anon_cred, dh_params);
Glauber Costa 47b075
-
Glauber Costa 47b075
-    return anon_cred;
Glauber Costa 47b075
 }
Glauber Costa 47b075
 
Glauber Costa 47b075
 
Glauber Costa 47b075
-static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(VncState *vs)
Glauber Costa 47b075
-{
Glauber Costa 47b075
-    gnutls_certificate_credentials_t x509_cred;
Glauber Costa 47b075
-    int ret;
Glauber Costa 47b075
-
Glauber Costa 47b075
-    if (!vs->vd->x509cacert) {
Glauber Costa 47b075
-	VNC_DEBUG("No CA x509 certificate specified\n");
Glauber Costa 47b075
-	return NULL;
Glauber Costa 47b075
-    }
Glauber Costa 47b075
-    if (!vs->vd->x509cert) {
Glauber Costa 47b075
-	VNC_DEBUG("No server x509 certificate specified\n");
Glauber Costa 47b075
-	return NULL;
Glauber Costa 47b075
-    }
Glauber Costa 47b075
-    if (!vs->vd->x509key) {
Glauber Costa 47b075
-	VNC_DEBUG("No server private key specified\n");
Glauber Costa 47b075
-	return NULL;
Glauber Costa 47b075
-    }
Glauber Costa 47b075
-
Glauber Costa 47b075
-    if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) {
Glauber Costa 47b075
-	VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
Glauber Costa 47b075
-	return NULL;
Glauber Costa 47b075
-    }
Glauber Costa 47b075
-    if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred,
Glauber Costa 47b075
-						      vs->vd->x509cacert,
Glauber Costa 47b075
-						      GNUTLS_X509_FMT_PEM)) < 0) {
Glauber Costa 47b075
-	VNC_DEBUG("Cannot load CA certificate %s\n", gnutls_strerror(ret));
Glauber Costa 47b075
-	gnutls_certificate_free_credentials(x509_cred);
Glauber Costa 47b075
-	return NULL;
Glauber Costa 47b075
-    }
Glauber Costa 47b075
-
Glauber Costa 47b075
-    if ((ret = gnutls_certificate_set_x509_key_file (x509_cred,
Glauber Costa 47b075
-						     vs->vd->x509cert,
Glauber Costa 47b075
-						     vs->vd->x509key,
Glauber Costa 47b075
-						     GNUTLS_X509_FMT_PEM)) < 0) {
Glauber Costa 47b075
-	VNC_DEBUG("Cannot load certificate & key %s\n", gnutls_strerror(ret));
Glauber Costa 47b075
-	gnutls_certificate_free_credentials(x509_cred);
Glauber Costa 47b075
-	return NULL;
Glauber Costa 47b075
-    }
Glauber Costa 47b075
-
Glauber Costa 47b075
-    if (vs->vd->x509cacrl) {
Glauber Costa 47b075
-	if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred,
Glauber Costa 47b075
-							vs->vd->x509cacrl,
Glauber Costa 47b075
-							GNUTLS_X509_FMT_PEM)) < 0) {
Glauber Costa 47b075
-	    VNC_DEBUG("Cannot load CRL %s\n", gnutls_strerror(ret));
Glauber Costa 47b075
-	    gnutls_certificate_free_credentials(x509_cred);
Glauber Costa 47b075
-	    return NULL;
Glauber Costa 47b075
-	}
Glauber Costa 47b075
-    }
Glauber Costa 47b075
-
Glauber Costa 47b075
-    gnutls_certificate_set_dh_params (x509_cred, dh_params);
Glauber Costa 47b075
-
Glauber Costa 47b075
-    return x509_cred;
Glauber Costa 47b075
-}
Glauber Costa 47b075
-
Glauber Costa 47b075
-static int vnc_validate_certificate(struct VncState *vs)
Glauber Costa 47b075
-{
Glauber Costa 47b075
-    int ret;
Glauber Costa 47b075
-    unsigned int status;
Glauber Costa 47b075
-    const gnutls_datum_t *certs;
Glauber Costa 47b075
-    unsigned int nCerts, i;
Glauber Costa 47b075
-    time_t now;
Glauber Costa 47b075
-
Glauber Costa 47b075
-    VNC_DEBUG("Validating client certificate\n");
Glauber Costa 47b075
-    if ((ret = gnutls_certificate_verify_peers2 (vs->tls_session, &status)) < 0) {
Glauber Costa 47b075
-	VNC_DEBUG("Verify failed %s\n", gnutls_strerror(ret));
Glauber Costa 47b075
-	return -1;
Glauber Costa 47b075
-    }
Glauber Costa 47b075
-
Glauber Costa 47b075
-    if ((now = time(NULL)) == ((time_t)-1)) {
Glauber Costa 47b075
-	return -1;
Glauber Costa 47b075
-    }
Glauber Costa 47b075
-
Glauber Costa 47b075
-    if (status != 0) {
Glauber Costa 47b075
-	if (status & GNUTLS_CERT_INVALID)
Glauber Costa 47b075
-	    VNC_DEBUG("The certificate is not trusted.\n");
Glauber Costa 47b075
-
Glauber Costa 47b075
-	if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
Glauber Costa 47b075
-	    VNC_DEBUG("The certificate hasn't got a known issuer.\n");
Glauber Costa 47b075
-
Glauber Costa 47b075
-	if (status & GNUTLS_CERT_REVOKED)
Glauber Costa 47b075
-	    VNC_DEBUG("The certificate has been revoked.\n");
Glauber Costa 47b075
-
Glauber Costa 47b075
-	if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
Glauber Costa 47b075
-	    VNC_DEBUG("The certificate uses an insecure algorithm\n");
Glauber Costa 47b075
-
Glauber Costa 47b075
-	return -1;
Glauber Costa 47b075
-    } else {
Glauber Costa 47b075
-	VNC_DEBUG("Certificate is valid!\n");
Glauber Costa 47b075
-    }
Glauber Costa 47b075
-
Glauber Costa 47b075
-    /* Only support x509 for now */
Glauber Costa 47b075
-    if (gnutls_certificate_type_get(vs->tls_session) != GNUTLS_CRT_X509)
Glauber Costa 47b075
-	return -1;
Glauber Costa 47b075
-
Glauber Costa 47b075
-    if (!(certs = gnutls_certificate_get_peers(vs->tls_session, &nCerts)))
Glauber Costa 47b075
-	return -1;
Glauber Costa 47b075
-
Glauber Costa 47b075
-    for (i = 0 ; i < nCerts ; i++) {
Glauber Costa 47b075
-	gnutls_x509_crt_t cert;
Glauber Costa 47b075
-	VNC_DEBUG ("Checking certificate chain %d\n", i);
Glauber Costa 47b075
-	if (gnutls_x509_crt_init (&cert) < 0)
Glauber Costa 47b075
-	    return -1;
Glauber Costa 47b075
-
Glauber Costa 47b075
-	if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) {
Glauber Costa 47b075
-	    gnutls_x509_crt_deinit (cert);
Glauber Costa 47b075
-	    return -1;
Glauber Costa 47b075
-	}
Glauber Costa 47b075
-
Glauber Costa 47b075
-	if (gnutls_x509_crt_get_expiration_time (cert) < now) {
Glauber Costa 47b075
-	    VNC_DEBUG("The certificate has expired\n");
Glauber Costa 47b075
-	    gnutls_x509_crt_deinit (cert);
Glauber Costa 47b075
-	    return -1;
Glauber Costa 47b075
-	}
Glauber Costa 47b075
-
Glauber Costa 47b075
-	if (gnutls_x509_crt_get_activation_time (cert) > now) {
Glauber Costa 47b075
-	    VNC_DEBUG("The certificate is not yet activated\n");
Glauber Costa 47b075
-	    gnutls_x509_crt_deinit (cert);
Glauber Costa 47b075
-	    return -1;
Glauber Costa 47b075
-	}
Glauber Costa 47b075
-
Glauber Costa 47b075
-	if (gnutls_x509_crt_get_activation_time (cert) > now) {
Glauber Costa 47b075
-	    VNC_DEBUG("The certificate is not yet activated\n");
Glauber Costa 47b075
-	    gnutls_x509_crt_deinit (cert);
Glauber Costa 47b075
-	    return -1;
Glauber Costa 47b075
-	}
Glauber Costa 47b075
-
Glauber Costa 47b075
-	gnutls_x509_crt_deinit (cert);
Glauber Costa 47b075
-    }
Glauber Costa 47b075
-
Glauber Costa 47b075
-    return 0;
Glauber Costa 47b075
-}
Glauber Costa 47b075
-
Glauber Costa 47b075
-
Glauber Costa 47b075
-static int start_auth_vencrypt_subauth(VncState *vs)
Glauber Costa 47b075
-{
Glauber Costa 47b075
-    switch (vs->vd->subauth) {
Glauber Costa 47b075
-    case VNC_AUTH_VENCRYPT_TLSNONE:
Glauber Costa 47b075
-    case VNC_AUTH_VENCRYPT_X509NONE:
Glauber Costa 47b075
-       VNC_DEBUG("Accept TLS auth none\n");
Glauber Costa 47b075
-       vnc_write_u32(vs, 0); /* Accept auth completion */
Glauber Costa 47b075
-       vnc_read_when(vs, protocol_client_init, 1);
Glauber Costa 47b075
-       break;
Glauber Costa 47b075
-
Glauber Costa 47b075
-    case VNC_AUTH_VENCRYPT_TLSVNC:
Glauber Costa 47b075
-    case VNC_AUTH_VENCRYPT_X509VNC:
Glauber Costa 47b075
-       VNC_DEBUG("Start TLS auth VNC\n");
Glauber Costa 47b075
-       return start_auth_vnc(vs);
Glauber Costa 47b075
-
Glauber Costa 47b075
-    default: /* Should not be possible, but just in case */
Glauber Costa 47b075
-       VNC_DEBUG("Reject auth %d\n", vs->vd->auth);
Glauber Costa 47b075
-       vnc_write_u8(vs, 1);
Glauber Costa 47b075
-       if (vs->minor >= 8) {
Glauber Costa 47b075
-           static const char err[] = "Unsupported authentication type";
Glauber Costa 47b075
-           vnc_write_u32(vs, sizeof(err));
Glauber Costa 47b075
-           vnc_write(vs, err, sizeof(err));
Glauber Costa 47b075
-       }
Glauber Costa 47b075
-       vnc_client_error(vs);
Glauber Costa 47b075
-    }
Glauber Costa 47b075
-
Glauber Costa 47b075
-    return 0;
Glauber Costa 47b075
-}
Glauber Costa 47b075
-
Glauber Costa 47b075
-static void vnc_handshake_io(void *opaque);
Glauber Costa 47b075
-
Glauber Costa 47b075
-static int vnc_continue_handshake(struct VncState *vs) {
Glauber Costa 47b075
-    int ret;
Glauber Costa 47b075
-
Glauber Costa 47b075
-    if ((ret = gnutls_handshake(vs->tls_session)) < 0) {
Glauber Costa 47b075
-       if (!gnutls_error_is_fatal(ret)) {
Glauber Costa 47b075
-           VNC_DEBUG("Handshake interrupted (blocking)\n");
Glauber Costa 47b075
-           if (!gnutls_record_get_direction(vs->tls_session))
Glauber Costa 47b075
-               qemu_set_fd_handler(vs->csock, vnc_handshake_io, NULL, vs);
Glauber Costa 47b075
-           else
Glauber Costa 47b075
-               qemu_set_fd_handler(vs->csock, NULL, vnc_handshake_io, vs);
Glauber Costa 47b075
-           return 0;
Glauber Costa 47b075
-       }
Glauber Costa 47b075
-       VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret));
Glauber Costa 47b075
-       vnc_client_error(vs);
Glauber Costa 47b075
-       return -1;
Glauber Costa 47b075
-    }
Glauber Costa 47b075
-
Glauber Costa 47b075
-    if (vs->vd->x509verify) {
Glauber Costa 47b075
-	if (vnc_validate_certificate(vs) < 0) {
Glauber Costa 47b075
-	    VNC_DEBUG("Client verification failed\n");
Glauber Costa 47b075
-	    vnc_client_error(vs);
Glauber Costa 47b075
-	    return -1;
Glauber Costa 47b075
-	} else {
Glauber Costa 47b075
-	    VNC_DEBUG("Client verification passed\n");
Glauber Costa 47b075
-	}
Glauber Costa 47b075
-    }
Glauber Costa 47b075
-
Glauber Costa 47b075
-    VNC_DEBUG("Handshake done, switching to TLS data mode\n");
Glauber Costa 47b075
-    vs->wiremode = VNC_WIREMODE_TLS;
Glauber Costa 47b075
-    qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
Glauber Costa 47b075
-
Glauber Costa 47b075
-    return start_auth_vencrypt_subauth(vs);
Glauber Costa 47b075
-}
Glauber Costa 47b075
-
Glauber Costa 47b075
-static void vnc_handshake_io(void *opaque) {
Glauber Costa 47b075
-    struct VncState *vs = (struct VncState *)opaque;
Glauber Costa 47b075
-
Glauber Costa 47b075
-    VNC_DEBUG("Handshake IO continue\n");
Glauber Costa 47b075
-    vnc_continue_handshake(vs);
Glauber Costa 47b075
-}
Glauber Costa 47b075
-
Glauber Costa 47b075
-#define NEED_X509_AUTH(vs)			      \
Glauber Costa 47b075
-    ((vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509NONE ||   \
Glauber Costa 47b075
-     (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509VNC ||    \
Glauber Costa 47b075
-     (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509PLAIN)
Glauber Costa 47b075
-
Glauber Costa 47b075
-
Glauber Costa 47b075
-static int vnc_start_tls(struct VncState *vs) {
Glauber Costa 47b075
-    static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
Glauber Costa 47b075
-    static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 };
Glauber Costa 47b075
-    static const int kx_anon[] = {GNUTLS_KX_ANON_DH, 0};
Glauber Costa 47b075
-    static const int kx_x509[] = {GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0};
Glauber Costa 47b075
-
Glauber Costa 47b075
-    VNC_DEBUG("Do TLS setup\n");
Glauber Costa 47b075
-    if (vnc_tls_initialize() < 0) {
Glauber Costa 47b075
-	VNC_DEBUG("Failed to init TLS\n");
Glauber Costa 47b075
-	vnc_client_error(vs);
Glauber Costa 47b075
-	return -1;
Glauber Costa 47b075
-    }
Glauber Costa 47b075
-    if (vs->tls_session == NULL) {
Glauber Costa 47b075
-	if (gnutls_init(&vs->tls_session, GNUTLS_SERVER) < 0) {
Glauber Costa 47b075
-	    vnc_client_error(vs);
Glauber Costa 47b075
-	    return -1;
Glauber Costa 47b075
-	}
Glauber Costa 47b075
-
Glauber Costa 47b075
-	if (gnutls_set_default_priority(vs->tls_session) < 0) {
Glauber Costa 47b075
-	    gnutls_deinit(vs->tls_session);
Glauber Costa 47b075
-	    vs->tls_session = NULL;
Glauber Costa 47b075
-	    vnc_client_error(vs);
Glauber Costa 47b075
-	    return -1;
Glauber Costa 47b075
-	}
Glauber Costa 47b075
-
Glauber Costa 47b075
-	if (gnutls_kx_set_priority(vs->tls_session, NEED_X509_AUTH(vs) ? kx_x509 : kx_anon) < 0) {
Glauber Costa 47b075
-	    gnutls_deinit(vs->tls_session);
Glauber Costa 47b075
-	    vs->tls_session = NULL;
Glauber Costa 47b075
-	    vnc_client_error(vs);
Glauber Costa 47b075
-	    return -1;
Glauber Costa 47b075
-	}
Glauber Costa 47b075
-
Glauber Costa 47b075
-	if (gnutls_certificate_type_set_priority(vs->tls_session, cert_type_priority) < 0) {
Glauber Costa 47b075
-	    gnutls_deinit(vs->tls_session);
Glauber Costa 47b075
-	    vs->tls_session = NULL;
Glauber Costa 47b075
-	    vnc_client_error(vs);
Glauber Costa 47b075
-	    return -1;
Glauber Costa 47b075
-	}
Glauber Costa 47b075
-
Glauber Costa 47b075
-	if (gnutls_protocol_set_priority(vs->tls_session, protocol_priority) < 0) {
Glauber Costa 47b075
-	    gnutls_deinit(vs->tls_session);
Glauber Costa 47b075
-	    vs->tls_session = NULL;
Glauber Costa 47b075
-	    vnc_client_error(vs);
Glauber Costa 47b075
-	    return -1;
Glauber Costa 47b075
-	}
Glauber Costa 47b075
-
Glauber Costa 47b075
-	if (NEED_X509_AUTH(vs)) {
Glauber Costa 47b075
-	    gnutls_certificate_server_credentials x509_cred = vnc_tls_initialize_x509_cred(vs);
Glauber Costa 47b075
-	    if (!x509_cred) {
Glauber Costa 47b075
-		gnutls_deinit(vs->tls_session);
Glauber Costa 47b075
-		vs->tls_session = NULL;
Glauber Costa 47b075
-		vnc_client_error(vs);
Glauber Costa 47b075
-		return -1;
Glauber Costa 47b075
-	    }
Glauber Costa 47b075
-	    if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) {
Glauber Costa 47b075
-		gnutls_deinit(vs->tls_session);
Glauber Costa 47b075
-		vs->tls_session = NULL;
Glauber Costa 47b075
-		gnutls_certificate_free_credentials(x509_cred);
Glauber Costa 47b075
-		vnc_client_error(vs);
Glauber Costa 47b075
-		return -1;
Glauber Costa 47b075
-	    }
Glauber Costa 47b075
-	    if (vs->vd->x509verify) {
Glauber Costa 47b075
-		VNC_DEBUG("Requesting a client certificate\n");
Glauber Costa 47b075
-		gnutls_certificate_server_set_request (vs->tls_session, GNUTLS_CERT_REQUEST);
Glauber Costa 47b075
-	    }
Glauber Costa 47b075
-
Glauber Costa 47b075
-	} else {
Glauber Costa 47b075
-	    gnutls_anon_server_credentials anon_cred = vnc_tls_initialize_anon_cred();
Glauber Costa 47b075
-	    if (!anon_cred) {
Glauber Costa 47b075
-		gnutls_deinit(vs->tls_session);
Glauber Costa 47b075
-		vs->tls_session = NULL;
Glauber Costa 47b075
-		vnc_client_error(vs);
Glauber Costa 47b075
-		return -1;
Glauber Costa 47b075
-	    }
Glauber Costa 47b075
-	    if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_ANON, anon_cred) < 0) {
Glauber Costa 47b075
-		gnutls_deinit(vs->tls_session);
Glauber Costa 47b075
-		vs->tls_session = NULL;
Glauber Costa 47b075
-		gnutls_anon_free_server_credentials(anon_cred);
Glauber Costa 47b075
-		vnc_client_error(vs);
Glauber Costa 47b075
-		return -1;
Glauber Costa 47b075
-	    }
Glauber Costa 47b075
-	}
Glauber Costa 47b075
-
Glauber Costa 47b075
-	gnutls_transport_set_ptr(vs->tls_session, (gnutls_transport_ptr_t)vs);
Glauber Costa 47b075
-	gnutls_transport_set_push_function(vs->tls_session, vnc_tls_push);
Glauber Costa 47b075
-	gnutls_transport_set_pull_function(vs->tls_session, vnc_tls_pull);
Glauber Costa 47b075
-    }
Glauber Costa 47b075
-
Glauber Costa 47b075
-    VNC_DEBUG("Start TLS handshake process\n");
Glauber Costa 47b075
-    return vnc_continue_handshake(vs);
Glauber Costa 47b075
-}
Glauber Costa 47b075
-
Glauber Costa 47b075
-static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len)
Glauber Costa 47b075
-{
Glauber Costa 47b075
-    int auth = read_u32(data, 0);
Glauber Costa 47b075
-
Glauber Costa 47b075
-    if (auth != vs->vd->subauth) {
Glauber Costa 47b075
-	VNC_DEBUG("Rejecting auth %d\n", auth);
Glauber Costa 47b075
-	vnc_write_u8(vs, 0); /* Reject auth */
Glauber Costa 47b075
-	vnc_flush(vs);
Glauber Costa 47b075
-	vnc_client_error(vs);
Glauber Costa 47b075
-    } else {
Glauber Costa 47b075
-	VNC_DEBUG("Accepting auth %d, starting handshake\n", auth);
Glauber Costa 47b075
-	vnc_write_u8(vs, 1); /* Accept auth */
Glauber Costa 47b075
-	vnc_flush(vs);
Glauber Costa 47b075
-
Glauber Costa 47b075
-	if (vnc_start_tls(vs) < 0) {
Glauber Costa 47b075
-	    VNC_DEBUG("Failed to complete TLS\n");
Glauber Costa 47b075
-	    return 0;
Glauber Costa 47b075
-	}
Glauber Costa 47b075
-    }
Glauber Costa 47b075
-    return 0;
Glauber Costa 47b075
-}
Glauber Costa 47b075
-
Glauber Costa 47b075
-static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len)
Glauber Costa 47b075
-{
Glauber Costa 47b075
-    if (data[0] != 0 ||
Glauber Costa 47b075
-	data[1] != 2) {
Glauber Costa 47b075
-	VNC_DEBUG("Unsupported VeNCrypt protocol %d.%d\n", (int)data[0], (int)data[1]);
Glauber Costa 47b075
-	vnc_write_u8(vs, 1); /* Reject version */
Glauber Costa 47b075
-	vnc_flush(vs);
Glauber Costa 47b075
-	vnc_client_error(vs);
Glauber Costa 47b075
-    } else {
Glauber Costa 47b075
-	VNC_DEBUG("Sending allowed auth %d\n", vs->vd->subauth);
Glauber Costa 47b075
-	vnc_write_u8(vs, 0); /* Accept version */
Glauber Costa 47b075
-	vnc_write_u8(vs, 1); /* Number of sub-auths */
Glauber Costa 47b075
-	vnc_write_u32(vs, vs->vd->subauth); /* The supported auth */
Glauber Costa 47b075
-	vnc_flush(vs);
Glauber Costa 47b075
-	vnc_read_when(vs, protocol_client_vencrypt_auth, 4);
Glauber Costa 47b075
-    }
Glauber Costa 47b075
-    return 0;
Glauber Costa 47b075
-}
Glauber Costa 47b075
-
Glauber Costa 47b075
-static int start_auth_vencrypt(VncState *vs)
Glauber Costa 47b075
-{
Glauber Costa 47b075
-    /* Send VeNCrypt version 0.2 */
Glauber Costa 47b075
-    vnc_write_u8(vs, 0);
Glauber Costa 47b075
-    vnc_write_u8(vs, 2);
Glauber Costa 47b075
-
Glauber Costa 47b075
-    vnc_read_when(vs, protocol_client_vencrypt_init, 2);
Glauber Costa 47b075
-    return 0;
Glauber Costa 47b075
-}
Glauber Costa 47b075
-#endif /* CONFIG_VNC_TLS */
Glauber Costa 47b075
-
Glauber Costa 47b075
 static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
Glauber Costa 47b075
 {
Glauber Costa 47b075
     /* We only advertise 1 auth scheme at a time, so client
Glauber Costa 47b075
@@ -2163,17 +1707,19 @@ static int protocol_client_auth(VncState
Glauber Costa 47b075
                vnc_write_u32(vs, 0); /* Accept auth completion */
Glauber Costa 47b075
                vnc_flush(vs);
Glauber Costa 47b075
            }
Glauber Costa 47b075
-           vnc_read_when(vs, protocol_client_init, 1);
Glauber Costa 47b075
+           start_client_init(vs);
Glauber Costa 47b075
            break;
Glauber Costa 47b075
 
Glauber Costa 47b075
        case VNC_AUTH_VNC:
Glauber Costa 47b075
            VNC_DEBUG("Start VNC auth\n");
Glauber Costa 47b075
-           return start_auth_vnc(vs);
Glauber Costa 47b075
+           start_auth_vnc(vs);
Glauber Costa 47b075
+           break;
Glauber Costa 47b075
 
Glauber Costa 47b075
 #ifdef CONFIG_VNC_TLS
Glauber Costa 47b075
        case VNC_AUTH_VENCRYPT:
Glauber Costa 47b075
            VNC_DEBUG("Accept VeNCrypt auth\n");;
Glauber Costa 47b075
-           return start_auth_vencrypt(vs);
Glauber Costa 47b075
+           start_auth_vencrypt(vs);
Glauber Costa 47b075
+           break;
Glauber Costa 47b075
 #endif /* CONFIG_VNC_TLS */
Glauber Costa 47b075
 
Glauber Costa 47b075
        default: /* Should not be possible, but just in case */
Glauber Costa 47b075
@@ -2226,7 +1772,7 @@ static int protocol_version(VncState *vs
Glauber Costa 47b075
             VNC_DEBUG("Tell client auth none\n");
Glauber Costa 47b075
             vnc_write_u32(vs, vs->vd->auth);
Glauber Costa 47b075
             vnc_flush(vs);
Glauber Costa 47b075
-            vnc_read_when(vs, protocol_client_init, 1);
Glauber Costa 47b075
+	    start_client_init(vs);
Glauber Costa 47b075
        } else if (vs->vd->auth == VNC_AUTH_VNC) {
Glauber Costa 47b075
             VNC_DEBUG("Tell client VNC auth\n");
Glauber Costa 47b075
             vnc_write_u32(vs, vs->vd->auth);
Glauber Costa 47b075
@@ -2328,61 +1874,6 @@ void vnc_display_init(DisplayState *ds)
Glauber Costa 47b075
     register_displaychangelistener(ds, dcl);
Glauber Costa 47b075
 }
Glauber Costa 47b075
 
Glauber Costa 47b075
-#ifdef CONFIG_VNC_TLS
Glauber Costa 47b075
-static int vnc_set_x509_credential(VncDisplay *vs,
Glauber Costa 47b075
-				   const char *certdir,
Glauber Costa 47b075
-				   const char *filename,
Glauber Costa 47b075
-				   char **cred,
Glauber Costa 47b075
-				   int ignoreMissing)
Glauber Costa 47b075
-{
Glauber Costa 47b075
-    struct stat sb;
Glauber Costa 47b075
-
Glauber Costa 47b075
-    if (*cred) {
Glauber Costa 47b075
-	qemu_free(*cred);
Glauber Costa 47b075
-	*cred = NULL;
Glauber Costa 47b075
-    }
Glauber Costa 47b075
-
Glauber Costa 47b075
-    *cred = qemu_malloc(strlen(certdir) + strlen(filename) + 2);
Glauber Costa 47b075
-
Glauber Costa 47b075
-    strcpy(*cred, certdir);
Glauber Costa 47b075
-    strcat(*cred, "/");
Glauber Costa 47b075
-    strcat(*cred, filename);
Glauber Costa 47b075
-
Glauber Costa 47b075
-    VNC_DEBUG("Check %s\n", *cred);
Glauber Costa 47b075
-    if (stat(*cred, &sb) < 0) {
Glauber Costa 47b075
-	qemu_free(*cred);
Glauber Costa 47b075
-	*cred = NULL;
Glauber Costa 47b075
-	if (ignoreMissing && errno == ENOENT)
Glauber Costa 47b075
-	    return 0;
Glauber Costa 47b075
-	return -1;
Glauber Costa 47b075
-    }
Glauber Costa 47b075
-
Glauber Costa 47b075
-    return 0;
Glauber Costa 47b075
-}
Glauber Costa 47b075
-
Glauber Costa 47b075
-static int vnc_set_x509_credential_dir(VncDisplay *vs,
Glauber Costa 47b075
-				       const char *certdir)
Glauber Costa 47b075
-{
Glauber Costa 47b075
-    if (vnc_set_x509_credential(vs, certdir, X509_CA_CERT_FILE, &vs->x509cacert, 0) < 0)
Glauber Costa 47b075
-	goto cleanup;
Glauber Costa 47b075
-    if (vnc_set_x509_credential(vs, certdir, X509_CA_CRL_FILE, &vs->x509cacrl, 1) < 0)
Glauber Costa 47b075
-	goto cleanup;
Glauber Costa 47b075
-    if (vnc_set_x509_credential(vs, certdir, X509_SERVER_CERT_FILE, &vs->x509cert, 0) < 0)
Glauber Costa 47b075
-	goto cleanup;
Glauber Costa 47b075
-    if (vnc_set_x509_credential(vs, certdir, X509_SERVER_KEY_FILE, &vs->x509key, 0) < 0)
Glauber Costa 47b075
-	goto cleanup;
Glauber Costa 47b075
-
Glauber Costa 47b075
-    return 0;
Glauber Costa 47b075
-
Glauber Costa 47b075
- cleanup:
Glauber Costa 47b075
-    qemu_free(vs->x509cacert);
Glauber Costa 47b075
-    qemu_free(vs->x509cacrl);
Glauber Costa 47b075
-    qemu_free(vs->x509cert);
Glauber Costa 47b075
-    qemu_free(vs->x509key);
Glauber Costa 47b075
-    vs->x509cacert = vs->x509cacrl = vs->x509cert = vs->x509key = NULL;
Glauber Costa 47b075
-    return -1;
Glauber Costa 47b075
-}
Glauber Costa 47b075
-#endif /* CONFIG_VNC_TLS */
Glauber Costa 47b075
 
Glauber Costa 47b075
 void vnc_display_close(DisplayState *ds)
Glauber Costa 47b075
 {
Glauber Costa 47b075
@@ -2402,7 +1893,7 @@ void vnc_display_close(DisplayState *ds)
Glauber Costa 47b075
     vs->auth = VNC_AUTH_INVALID;
Glauber Costa 47b075
 #ifdef CONFIG_VNC_TLS
Glauber Costa 47b075
     vs->subauth = VNC_AUTH_INVALID;
Glauber Costa 47b075
-    vs->x509verify = 0;
Glauber Costa 47b075
+    vs->tls.x509verify = 0;
Glauber Costa 47b075
 #endif
Glauber Costa 47b075
 }
Glauber Costa 47b075
 
Glauber Costa 47b075
@@ -2458,7 +1949,7 @@ int vnc_display_open(DisplayState *ds, c
Glauber Costa 47b075
 	    char *start, *end;
Glauber Costa 47b075
 	    x509 = 1; /* Require x509 certificates */
Glauber Costa 47b075
 	    if (strncmp(options, "x509verify", 10) == 0)
Glauber Costa 47b075
-	        vs->x509verify = 1; /* ...and verify client certs */
Glauber Costa 47b075
+	        vs->tls.x509verify = 1; /* ...and verify client certs */
Glauber Costa 47b075
 
Glauber Costa 47b075
 	    /* Now check for 'x509=/some/path' postfix
Glauber Costa 47b075
 	     * and use that to setup x509 certificate/key paths */
Glauber Costa 47b075
@@ -2469,7 +1960,7 @@ int vnc_display_open(DisplayState *ds, c
Glauber Costa 47b075
 		char *path = qemu_strndup(start + 1, len);
Glauber Costa 47b075
 
Glauber Costa 47b075
 		VNC_DEBUG("Trying certificate path '%s'\n", path);
Glauber Costa 47b075
-		if (vnc_set_x509_credential_dir(vs, path) < 0) {
Glauber Costa 47b075
+		if (vnc_tls_set_x509_creds_dir(vs, path) < 0) {
Glauber Costa 47b075
 		    fprintf(stderr, "Failed to find x509 certificates/keys in %s\n", path);
Glauber Costa 47b075
 		    qemu_free(path);
Glauber Costa 47b075
 		    qemu_free(vs->display);
Glauber Costa 47b075
Index: qemu-kvm-0.10/qemu/vnc.h
Glauber Costa 47b075
===================================================================
Glauber Costa 47b075
--- qemu-kvm-0.10.orig/qemu/vnc.h
Glauber Costa 47b075
+++ qemu-kvm-0.10/qemu/vnc.h
Glauber Costa 47b075
@@ -32,13 +32,16 @@
Glauber Costa 47b075
 #include "audio/audio.h"
Glauber Costa 47b075
 #include <zlib.h>
Glauber Costa 47b075
 
Glauber Costa 47b075
-#ifdef CONFIG_VNC_TLS
Glauber Costa 47b075
-#include <gnutls/gnutls.h>
Glauber Costa 47b075
-#include <gnutls/x509.h>
Glauber Costa 47b075
-#endif /* CONFIG_VNC_TLS */
Glauber Costa 47b075
-
Glauber Costa 47b075
 #include "keymaps.h"
Glauber Costa 47b075
 
Glauber Costa 47b075
+// #define _VNC_DEBUG 1
Glauber Costa 47b075
+
Glauber Costa 47b075
+#ifdef _VNC_DEBUG
Glauber Costa 47b075
+#define VNC_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
Glauber Costa 47b075
+#else
Glauber Costa 47b075
+#define VNC_DEBUG(fmt, ...) do { } while (0)
Glauber Costa 47b075
+#endif
Glauber Costa 47b075
+
Glauber Costa 47b075
 /*****************************************************************************
Glauber Costa 47b075
  *
Glauber Costa 47b075
  * Core data structures
Glauber Costa 47b075
@@ -72,6 +75,11 @@ typedef void VncSendHextileTile(VncState
Glauber Costa 47b075
 
Glauber Costa 47b075
 typedef struct VncDisplay VncDisplay;
Glauber Costa 47b075
 
Glauber Costa 47b075
+#ifdef CONFIG_VNC_TLS
Glauber Costa 47b075
+#include "vnc-tls.h"
Glauber Costa 47b075
+#include "vnc-auth-vencrypt.h"
Glauber Costa 47b075
+#endif
Glauber Costa 47b075
+
Glauber Costa 47b075
 struct VncDisplay
Glauber Costa 47b075
 {
Glauber Costa 47b075
     int lsock;
Glauber Costa 47b075
@@ -83,13 +91,8 @@ struct VncDisplay
Glauber Costa 47b075
     char *password;
Glauber Costa 47b075
     int auth;
Glauber Costa 47b075
 #ifdef CONFIG_VNC_TLS
Glauber Costa 47b075
-    int subauth;
Glauber Costa 47b075
-    int x509verify;
Glauber Costa 47b075
-
Glauber Costa 47b075
-    char *x509cacert;
Glauber Costa 47b075
-    char *x509cacrl;
Glauber Costa 47b075
-    char *x509cert;
Glauber Costa 47b075
-    char *x509key;
Glauber Costa 47b075
+    int subauth; /* Used by VeNCrypt */
Glauber Costa 47b075
+    VncDisplayTLS tls;
Glauber Costa 47b075
 #endif
Glauber Costa 47b075
 };
Glauber Costa 47b075
 
Glauber Costa 47b075
@@ -117,8 +120,7 @@ struct VncState
Glauber Costa 47b075
     char challenge[VNC_AUTH_CHALLENGE_SIZE];
Glauber Costa 47b075
 
Glauber Costa 47b075
 #ifdef CONFIG_VNC_TLS
Glauber Costa 47b075
-    int wiremode;
Glauber Costa 47b075
-    gnutls_session_t tls_session;
Glauber Costa 47b075
+    VncStateTLS tls;
Glauber Costa 47b075
 #endif
Glauber Costa 47b075
 
Glauber Costa 47b075
     Buffer output;
Glauber Costa 47b075
@@ -162,12 +164,6 @@ enum {
Glauber Costa 47b075
     VNC_AUTH_VENCRYPT = 19
Glauber Costa 47b075
 };
Glauber Costa 47b075
 
Glauber Costa 47b075
-#ifdef CONFIG_VNC_TLS
Glauber Costa 47b075
-enum {
Glauber Costa 47b075
-    VNC_WIREMODE_CLEAR,
Glauber Costa 47b075
-    VNC_WIREMODE_TLS,
Glauber Costa 47b075
-};
Glauber Costa 47b075
-
Glauber Costa 47b075
 enum {
Glauber Costa 47b075
     VNC_AUTH_VENCRYPT_PLAIN = 256,
Glauber Costa 47b075
     VNC_AUTH_VENCRYPT_TLSNONE = 257,
Glauber Costa 47b075
@@ -178,12 +174,6 @@ enum {
Glauber Costa 47b075
     VNC_AUTH_VENCRYPT_X509PLAIN = 262,
Glauber Costa 47b075
 };
Glauber Costa 47b075
 
Glauber Costa 47b075
-#define X509_CA_CERT_FILE "ca-cert.pem"
Glauber Costa 47b075
-#define X509_CA_CRL_FILE "ca-crl.pem"
Glauber Costa 47b075
-#define X509_SERVER_KEY_FILE "server-key.pem"
Glauber Costa 47b075
-#define X509_SERVER_CERT_FILE "server-cert.pem"
Glauber Costa 47b075
-
Glauber Costa 47b075
-#endif /* CONFIG_VNC_TLS */
Glauber Costa 47b075
 
Glauber Costa 47b075
 /*****************************************************************************
Glauber Costa 47b075
  *
Glauber Costa 47b075
@@ -254,4 +244,38 @@ enum {
Glauber Costa 47b075
 #define VNC_FEATURE_ZLIB_MASK                (1 << VNC_FEATURE_ZLIB)
Glauber Costa 47b075
 #define VNC_FEATURE_COPYRECT_MASK            (1 << VNC_FEATURE_COPYRECT)
Glauber Costa 47b075
 
Glauber Costa 47b075
+
Glauber Costa 47b075
+/*****************************************************************************
Glauber Costa 47b075
+ *
Glauber Costa 47b075
+ * Internal APIs
Glauber Costa 47b075
+ *
Glauber Costa 47b075
+ *****************************************************************************/
Glauber Costa 47b075
+
Glauber Costa 47b075
+/* Event loop functions */
Glauber Costa 47b075
+void vnc_client_read(void *opaque);
Glauber Costa 47b075
+void vnc_client_write(void *opaque);
Glauber Costa 47b075
+
Glauber Costa 47b075
+
Glauber Costa 47b075
+/* Protocol I/O functions */
Glauber Costa 47b075
+void vnc_write(VncState *vs, const void *data, size_t len);
Glauber Costa 47b075
+void vnc_write_u32(VncState *vs, uint32_t value);
Glauber Costa 47b075
+void vnc_write_s32(VncState *vs, int32_t value);
Glauber Costa 47b075
+void vnc_write_u16(VncState *vs, uint16_t value);
Glauber Costa 47b075
+void vnc_write_u8(VncState *vs, uint8_t value);
Glauber Costa 47b075
+void vnc_flush(VncState *vs);
Glauber Costa 47b075
+void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting);
Glauber Costa 47b075
+
Glauber Costa 47b075
+
Glauber Costa 47b075
+/* Buffer I/O functions */
Glauber Costa 47b075
+uint8_t read_u8(uint8_t *data, size_t offset);
Glauber Costa 47b075
+uint16_t read_u16(uint8_t *data, size_t offset);
Glauber Costa 47b075
+int32_t read_s32(uint8_t *data, size_t offset);
Glauber Costa 47b075
+uint32_t read_u32(uint8_t *data, size_t offset);
Glauber Costa 47b075
+
Glauber Costa 47b075
+/* Protocol stage functions */
Glauber Costa 47b075
+void vnc_client_error(VncState *vs);
Glauber Costa 47b075
+
Glauber Costa 47b075
+void start_client_init(VncState *vs);
Glauber Costa 47b075
+void start_auth_vnc(VncState *vs);
Glauber Costa 47b075
+
Glauber Costa 47b075
 #endif /* __QEMU_VNC_H */