#include "qemu-x509.h"
#include "vnc.h"
-#include "qemu_socket.h"
+#include "qemu/sockets.h"
#if defined(_VNC_DEBUG) && _VNC_DEBUG >= 2
/* Very verbose, so only enabled for _VNC_DEBUG >= 2 */
if (gnutls_global_init () < 0)
return 0;
- /* XXX ought to re-generate diffie-hellmen params periodically */
+ /* XXX ought to re-generate diffie-hellman params periodically */
if (gnutls_dh_params_init (&dh_params) < 0)
return 0;
if (gnutls_dh_params_generate2 (dh_params, DH_BITS) < 0)
int ret;
retry:
- ret = recv(vs->csock, data, len, 0);
+ ret = qemu_recv(vs->csock, data, len, 0);
if (ret < 0) {
if (errno == EINTR)
goto retry;
}
-static gnutls_anon_server_credentials vnc_tls_initialize_anon_cred(void)
+static gnutls_anon_server_credentials_t vnc_tls_initialize_anon_cred(void)
{
- gnutls_anon_server_credentials anon_cred;
+ gnutls_anon_server_credentials_t anon_cred;
int ret;
if ((ret = gnutls_anon_allocate_server_credentials(&anon_cred)) < 0) {
if (i == 0) {
size_t dnameSize = 1024;
- vs->tls.dname = qemu_malloc(dnameSize);
+ vs->tls.dname = g_malloc(dnameSize);
requery:
if ((ret = gnutls_x509_crt_get_dn (cert, vs->tls.dname, &dnameSize)) != 0) {
if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
- vs->tls.dname = qemu_realloc(vs->tls.dname, dnameSize);
+ vs->tls.dname = g_realloc(vs->tls.dname, dnameSize);
goto requery;
}
gnutls_x509_crt_deinit (cert);
return 0;
}
+#if defined(GNUTLS_VERSION_NUMBER) && \
+ GNUTLS_VERSION_NUMBER >= 0x020200 /* 2.2.0 */
+
+static int vnc_set_gnutls_priority(gnutls_session_t s, int x509)
+{
+ const char *priority = x509 ? "NORMAL" : "NORMAL:+ANON-DH";
+ int rc;
+
+ rc = gnutls_priority_set_direct(s, priority, NULL);
+ if (rc != GNUTLS_E_SUCCESS) {
+ return -1;
+ }
+ return 0;
+}
+
+#else
+
+static int vnc_set_gnutls_priority(gnutls_session_t s, int x509)
+{
+ static const int cert_types[] = { GNUTLS_CRT_X509, 0 };
+ static const int protocols[] = {
+ GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0
+ };
+ static const int kx_anon[] = { GNUTLS_KX_ANON_DH, 0 };
+ static const int kx_x509[] = {
+ GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA,
+ GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0
+ };
+ int rc;
+
+ rc = gnutls_kx_set_priority(s, x509 ? kx_x509 : kx_anon);
+ if (rc != GNUTLS_E_SUCCESS) {
+ return -1;
+ }
+
+ rc = gnutls_certificate_type_set_priority(s, cert_types);
+ if (rc != GNUTLS_E_SUCCESS) {
+ return -1;
+ }
+
+ rc = gnutls_protocol_set_priority(s, protocols);
+ if (rc != GNUTLS_E_SUCCESS) {
+ return -1;
+ }
+ return 0;
+}
+
+#endif
int vnc_tls_client_setup(struct VncState *vs,
int needX509Creds) {
- static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
- static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 };
- static const int kx_anon[] = {GNUTLS_KX_ANON_DH, 0};
- static const int kx_x509[] = {GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0};
+ VncStateTLS *tls;
VNC_DEBUG("Do TLS setup\n");
+#ifdef CONFIG_VNC_WS
+ if (vs->websocket) {
+ tls = &vs->ws_tls;
+ } else
+#endif /* CONFIG_VNC_WS */
+ {
+ tls = &vs->tls;
+ }
if (vnc_tls_initialize() < 0) {
VNC_DEBUG("Failed to init TLS\n");
vnc_client_error(vs);
return -1;
}
- if (vs->tls.session == NULL) {
- if (gnutls_init(&vs->tls.session, GNUTLS_SERVER) < 0) {
- vnc_client_error(vs);
- return -1;
- }
-
- if (gnutls_set_default_priority(vs->tls.session) < 0) {
- gnutls_deinit(vs->tls.session);
- vs->tls.session = NULL;
- vnc_client_error(vs);
- return -1;
- }
-
- if (gnutls_kx_set_priority(vs->tls.session, needX509Creds ? kx_x509 : kx_anon) < 0) {
- gnutls_deinit(vs->tls.session);
- vs->tls.session = NULL;
+ if (tls->session == NULL) {
+ if (gnutls_init(&tls->session, GNUTLS_SERVER) < 0) {
vnc_client_error(vs);
return -1;
}
- if (gnutls_certificate_type_set_priority(vs->tls.session, cert_type_priority) < 0) {
- gnutls_deinit(vs->tls.session);
- vs->tls.session = NULL;
+ if (gnutls_set_default_priority(tls->session) < 0) {
+ gnutls_deinit(tls->session);
+ tls->session = NULL;
vnc_client_error(vs);
return -1;
}
- if (gnutls_protocol_set_priority(vs->tls.session, protocol_priority) < 0) {
- gnutls_deinit(vs->tls.session);
- vs->tls.session = NULL;
+ if (vnc_set_gnutls_priority(tls->session, needX509Creds) < 0) {
+ gnutls_deinit(tls->session);
+ tls->session = NULL;
vnc_client_error(vs);
return -1;
}
if (needX509Creds) {
gnutls_certificate_server_credentials x509_cred = vnc_tls_initialize_x509_cred(vs->vd);
if (!x509_cred) {
- gnutls_deinit(vs->tls.session);
- vs->tls.session = NULL;
+ gnutls_deinit(tls->session);
+ tls->session = NULL;
vnc_client_error(vs);
return -1;
}
- if (gnutls_credentials_set(vs->tls.session, GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) {
- gnutls_deinit(vs->tls.session);
- vs->tls.session = NULL;
+ if (gnutls_credentials_set(tls->session, GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) {
+ gnutls_deinit(tls->session);
+ tls->session = NULL;
gnutls_certificate_free_credentials(x509_cred);
vnc_client_error(vs);
return -1;
}
if (vs->vd->tls.x509verify) {
VNC_DEBUG("Requesting a client certificate\n");
- gnutls_certificate_server_set_request (vs->tls.session, GNUTLS_CERT_REQUEST);
+ gnutls_certificate_server_set_request (tls->session, GNUTLS_CERT_REQUEST);
}
} else {
- gnutls_anon_server_credentials anon_cred = vnc_tls_initialize_anon_cred();
+ gnutls_anon_server_credentials_t anon_cred = vnc_tls_initialize_anon_cred();
if (!anon_cred) {
- gnutls_deinit(vs->tls.session);
- vs->tls.session = NULL;
+ gnutls_deinit(tls->session);
+ tls->session = NULL;
vnc_client_error(vs);
return -1;
}
- if (gnutls_credentials_set(vs->tls.session, GNUTLS_CRD_ANON, anon_cred) < 0) {
- gnutls_deinit(vs->tls.session);
- vs->tls.session = NULL;
+ if (gnutls_credentials_set(tls->session, GNUTLS_CRD_ANON, anon_cred) < 0) {
+ gnutls_deinit(tls->session);
+ tls->session = NULL;
gnutls_anon_free_server_credentials(anon_cred);
vnc_client_error(vs);
return -1;
}
}
- gnutls_transport_set_ptr(vs->tls.session, (gnutls_transport_ptr_t)vs);
- gnutls_transport_set_push_function(vs->tls.session, vnc_tls_push);
- gnutls_transport_set_pull_function(vs->tls.session, vnc_tls_pull);
+ gnutls_transport_set_ptr(tls->session, (gnutls_transport_ptr_t)vs);
+ gnutls_transport_set_push_function(tls->session, vnc_tls_push);
+ gnutls_transport_set_pull_function(tls->session, vnc_tls_pull);
}
return 0;
}
vs->tls.session = NULL;
}
vs->tls.wiremode = VNC_WIREMODE_CLEAR;
- free(vs->tls.dname);
+ g_free(vs->tls.dname);
+#ifdef CONFIG_VNC_WS
+ if (vs->ws_tls.session) {
+ gnutls_deinit(vs->ws_tls.session);
+ vs->ws_tls.session = NULL;
+ }
+ vs->ws_tls.wiremode = VNC_WIREMODE_CLEAR;
+ g_free(vs->ws_tls.dname);
+#endif /* CONFIG_VNC_WS */
}
struct stat sb;
if (*cred) {
- qemu_free(*cred);
+ g_free(*cred);
*cred = NULL;
}
- *cred = qemu_malloc(strlen(certdir) + strlen(filename) + 2);
+ *cred = g_malloc(strlen(certdir) + strlen(filename) + 2);
strcpy(*cred, certdir);
strcat(*cred, "/");
VNC_DEBUG("Check %s\n", *cred);
if (stat(*cred, &sb) < 0) {
- qemu_free(*cred);
+ g_free(*cred);
*cred = NULL;
if (ignoreMissing && errno == ENOENT)
return 0;
return 0;
cleanup:
- qemu_free(vd->tls.x509cacert);
- qemu_free(vd->tls.x509cacrl);
- qemu_free(vd->tls.x509cert);
- qemu_free(vd->tls.x509key);
+ g_free(vd->tls.x509cacert);
+ g_free(vd->tls.x509cacrl);
+ g_free(vd->tls.x509cert);
+ g_free(vd->tls.x509key);
vd->tls.x509cacert = vd->tls.x509cacrl = vd->tls.x509cert = vd->tls.x509key = NULL;
return -1;
}