ui: convert VNC server to use QIOChannelTLS
Switch VNC server over to using the QIOChannelTLS object for the TLS session. This removes all remaining VNC specific code for dealing with TLS handshakes. Reviewed-by: Gerd Hoffmann <kraxel@redhat.com> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
parent
04d2529da2
commit
2cc452281e
@ -63,71 +63,21 @@ static void start_auth_vencrypt_subauth(VncState *vs)
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean vnc_tls_handshake_io(QIOChannel *ioc,
|
||||
GIOCondition condition,
|
||||
void *opaque);
|
||||
|
||||
static int vnc_start_vencrypt_handshake(VncState *vs)
|
||||
static void vnc_tls_handshake_done(Object *source,
|
||||
Error *err,
|
||||
gpointer user_data)
|
||||
{
|
||||
Error *err = NULL;
|
||||
VncState *vs = user_data;
|
||||
|
||||
if (qcrypto_tls_session_handshake(vs->tls, &err) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
switch (qcrypto_tls_session_get_handshake_status(vs->tls)) {
|
||||
case QCRYPTO_TLS_HANDSHAKE_COMPLETE:
|
||||
VNC_DEBUG("Handshake done, checking credentials\n");
|
||||
if (qcrypto_tls_session_check_credentials(vs->tls, &err) < 0) {
|
||||
goto error;
|
||||
}
|
||||
VNC_DEBUG("Client verification passed, starting TLS I/O\n");
|
||||
if (vs->ioc_tag) {
|
||||
g_source_remove(vs->ioc_tag);
|
||||
}
|
||||
if (err) {
|
||||
VNC_DEBUG("Handshake failed %s\n",
|
||||
error_get_pretty(err));
|
||||
vnc_client_error(vs);
|
||||
} else {
|
||||
vs->ioc_tag = qio_channel_add_watch(
|
||||
vs->ioc, G_IO_IN | G_IO_OUT, vnc_client_io, vs, NULL);
|
||||
|
||||
start_auth_vencrypt_subauth(vs);
|
||||
break;
|
||||
|
||||
case QCRYPTO_TLS_HANDSHAKE_RECVING:
|
||||
VNC_DEBUG("Handshake interrupted (blocking read)\n");
|
||||
if (vs->ioc_tag) {
|
||||
g_source_remove(vs->ioc_tag);
|
||||
}
|
||||
vs->ioc_tag = qio_channel_add_watch(
|
||||
vs->ioc, G_IO_IN, vnc_tls_handshake_io, vs, NULL);
|
||||
break;
|
||||
|
||||
case QCRYPTO_TLS_HANDSHAKE_SENDING:
|
||||
VNC_DEBUG("Handshake interrupted (blocking write)\n");
|
||||
if (vs->ioc_tag) {
|
||||
g_source_remove(vs->ioc_tag);
|
||||
}
|
||||
vs->ioc_tag = qio_channel_add_watch(
|
||||
vs->ioc, G_IO_OUT, vnc_tls_handshake_io, vs, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
VNC_DEBUG("Handshake failed %s\n", error_get_pretty(err));
|
||||
error_free(err);
|
||||
vnc_client_error(vs);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static gboolean vnc_tls_handshake_io(QIOChannel *ioc G_GNUC_UNUSED,
|
||||
GIOCondition condition G_GNUC_UNUSED,
|
||||
void *opaque)
|
||||
{
|
||||
VncState *vs = (VncState *)opaque;
|
||||
|
||||
VNC_DEBUG("Handshake IO continue\n");
|
||||
vnc_start_vencrypt_handshake(vs);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
@ -142,33 +92,37 @@ static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len
|
||||
vnc_client_error(vs);
|
||||
} else {
|
||||
Error *err = NULL;
|
||||
QIOChannelTLS *tls;
|
||||
VNC_DEBUG("Accepting auth %d, setting up TLS for handshake\n", auth);
|
||||
vnc_write_u8(vs, 1); /* Accept auth */
|
||||
vnc_flush(vs);
|
||||
|
||||
vs->tls = qcrypto_tls_session_new(vs->vd->tlscreds,
|
||||
NULL,
|
||||
vs->vd->tlsaclname,
|
||||
QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
|
||||
&err);
|
||||
if (!vs->tls) {
|
||||
VNC_DEBUG("Failed to setup TLS %s\n",
|
||||
error_get_pretty(err));
|
||||
if (vs->ioc_tag) {
|
||||
g_source_remove(vs->ioc_tag);
|
||||
vs->ioc_tag = 0;
|
||||
}
|
||||
|
||||
tls = qio_channel_tls_new_server(
|
||||
vs->ioc,
|
||||
vs->vd->tlscreds,
|
||||
vs->vd->tlsaclname,
|
||||
&err);
|
||||
if (!tls) {
|
||||
VNC_DEBUG("Failed to setup TLS %s\n", error_get_pretty(err));
|
||||
error_free(err);
|
||||
vnc_client_error(vs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
qcrypto_tls_session_set_callbacks(vs->tls,
|
||||
vnc_tls_push,
|
||||
vnc_tls_pull,
|
||||
vs);
|
||||
|
||||
VNC_DEBUG("Start TLS VeNCrypt handshake process\n");
|
||||
if (vnc_start_vencrypt_handshake(vs) < 0) {
|
||||
VNC_DEBUG("Failed to start TLS handshake\n");
|
||||
return 0;
|
||||
}
|
||||
object_unref(OBJECT(vs->ioc));
|
||||
vs->ioc = QIO_CHANNEL(tls);
|
||||
vs->tls = qio_channel_tls_get_session(tls);
|
||||
|
||||
qio_channel_tls_handshake(tls,
|
||||
vnc_tls_handshake_done,
|
||||
vs,
|
||||
NULL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
97
ui/vnc-ws.c
97
ui/vnc-ws.c
@ -22,83 +22,60 @@
|
||||
#include "qemu/main-loop.h"
|
||||
#include "crypto/hash.h"
|
||||
|
||||
static int vncws_start_tls_handshake(VncState *vs)
|
||||
static void vncws_handshake_read(VncState *vs);
|
||||
|
||||
static void vncws_tls_handshake_done(Object *source,
|
||||
Error *err,
|
||||
gpointer user_data)
|
||||
{
|
||||
Error *err = NULL;
|
||||
VncState *vs = user_data;
|
||||
|
||||
if (qcrypto_tls_session_handshake(vs->tls, &err) < 0) {
|
||||
goto error;
|
||||
if (err) {
|
||||
VNC_DEBUG("Handshake failed %s\n", error_get_pretty(err));
|
||||
vnc_client_error(vs);
|
||||
} else {
|
||||
vs->ioc_tag = qio_channel_add_watch(
|
||||
QIO_CHANNEL(vs->ioc), G_IO_IN, vncws_handshake_io, vs, NULL);
|
||||
}
|
||||
|
||||
switch (qcrypto_tls_session_get_handshake_status(vs->tls)) {
|
||||
case QCRYPTO_TLS_HANDSHAKE_COMPLETE:
|
||||
VNC_DEBUG("Handshake done, checking credentials\n");
|
||||
if (qcrypto_tls_session_check_credentials(vs->tls, &err) < 0) {
|
||||
goto error;
|
||||
}
|
||||
VNC_DEBUG("Client verification passed, starting TLS I/O\n");
|
||||
if (vs->ioc_tag) {
|
||||
g_source_remove(vs->ioc_tag);
|
||||
}
|
||||
vs->ioc_tag = qio_channel_add_watch(
|
||||
vs->ioc, G_IO_IN, vncws_handshake_io, vs, NULL);
|
||||
break;
|
||||
|
||||
case QCRYPTO_TLS_HANDSHAKE_RECVING:
|
||||
VNC_DEBUG("Handshake interrupted (blocking read)\n");
|
||||
if (vs->ioc_tag) {
|
||||
g_source_remove(vs->ioc_tag);
|
||||
}
|
||||
vs->ioc_tag = qio_channel_add_watch(
|
||||
vs->ioc, G_IO_IN, vncws_tls_handshake_io, vs, NULL);
|
||||
break;
|
||||
|
||||
case QCRYPTO_TLS_HANDSHAKE_SENDING:
|
||||
VNC_DEBUG("Handshake interrupted (blocking write)\n");
|
||||
if (vs->ioc_tag) {
|
||||
g_source_remove(vs->ioc_tag);
|
||||
}
|
||||
vs->ioc_tag = qio_channel_add_watch(
|
||||
vs->ioc, G_IO_OUT, vncws_tls_handshake_io, vs, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
VNC_DEBUG("Handshake failed %s\n", error_get_pretty(err));
|
||||
error_free(err);
|
||||
vnc_client_error(vs);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
gboolean vncws_tls_handshake_io(QIOChannel *ioc G_GNUC_UNUSED,
|
||||
GIOCondition condition G_GNUC_UNUSED,
|
||||
void *opaque)
|
||||
{
|
||||
VncState *vs = (VncState *)opaque;
|
||||
VncState *vs = opaque;
|
||||
QIOChannelTLS *tls;
|
||||
Error *err = NULL;
|
||||
|
||||
vs->tls = qcrypto_tls_session_new(vs->vd->tlscreds,
|
||||
NULL,
|
||||
vs->vd->tlsaclname,
|
||||
QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
|
||||
&err);
|
||||
if (!vs->tls) {
|
||||
VNC_DEBUG("Failed to setup TLS %s\n",
|
||||
error_get_pretty(err));
|
||||
VNC_DEBUG("TLS Websocket connection required\n");
|
||||
if (vs->ioc_tag) {
|
||||
g_source_remove(vs->ioc_tag);
|
||||
vs->ioc_tag = 0;
|
||||
}
|
||||
|
||||
tls = qio_channel_tls_new_server(
|
||||
vs->ioc,
|
||||
vs->vd->tlscreds,
|
||||
vs->vd->tlsaclname,
|
||||
&err);
|
||||
if (!tls) {
|
||||
VNC_DEBUG("Failed to setup TLS %s\n", error_get_pretty(err));
|
||||
error_free(err);
|
||||
vnc_client_error(vs);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
qcrypto_tls_session_set_callbacks(vs->tls,
|
||||
vnc_tls_push,
|
||||
vnc_tls_pull,
|
||||
vs);
|
||||
|
||||
VNC_DEBUG("Start TLS WS handshake process\n");
|
||||
vncws_start_tls_handshake(vs);
|
||||
object_unref(OBJECT(vs->ioc));
|
||||
vs->ioc = QIO_CHANNEL(tls);
|
||||
vs->tls = qio_channel_tls_get_session(tls);
|
||||
|
||||
qio_channel_tls_handshake(tls,
|
||||
vncws_tls_handshake_done,
|
||||
vs,
|
||||
NULL);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
69
ui/vnc.c
69
ui/vnc.c
@ -1201,7 +1201,6 @@ void vnc_disconnect_finish(VncState *vs)
|
||||
vnc_tight_clear(vs);
|
||||
vnc_zrle_clear(vs);
|
||||
|
||||
qcrypto_tls_session_free(vs->tls);
|
||||
#ifdef CONFIG_VNC_SASL
|
||||
vnc_sasl_client_cleanup(vs);
|
||||
#endif /* CONFIG_VNC_SASL */
|
||||
@ -1267,38 +1266,6 @@ void vnc_client_error(VncState *vs)
|
||||
}
|
||||
|
||||
|
||||
ssize_t vnc_tls_pull(char *buf, size_t len, void *opaque)
|
||||
{
|
||||
VncState *vs = opaque;
|
||||
ssize_t ret = qio_channel_read(vs->ioc, buf, len, NULL);
|
||||
if (ret < 0) {
|
||||
if (ret == QIO_CHANNEL_ERR_BLOCK) {
|
||||
errno = EAGAIN;
|
||||
} else {
|
||||
errno = EIO;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
ssize_t vnc_tls_push(const char *buf, size_t len, void *opaque)
|
||||
{
|
||||
VncState *vs = opaque;
|
||||
ssize_t ret = qio_channel_write(vs->ioc, buf, len, NULL);
|
||||
if (ret < 0) {
|
||||
if (ret == QIO_CHANNEL_ERR_BLOCK) {
|
||||
errno = EAGAIN;
|
||||
} else {
|
||||
errno = EIO;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Called to write a chunk of data to the client socket. The data may
|
||||
* be the raw data, or may have already been encoded by SASL.
|
||||
@ -1318,21 +1285,8 @@ ssize_t vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen)
|
||||
{
|
||||
Error *err = NULL;
|
||||
ssize_t ret;
|
||||
if (vs->tls) {
|
||||
ret = qcrypto_tls_session_write(vs->tls, (const char *)data, datalen);
|
||||
if (ret < 0) {
|
||||
if (errno == EAGAIN) {
|
||||
ret = QIO_CHANNEL_ERR_BLOCK;
|
||||
} else {
|
||||
ret = -1;
|
||||
error_setg_errno(&err, errno, "%s",
|
||||
"Cannot write to TLS socket");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = qio_channel_write(
|
||||
vs->ioc, (const char *)data, datalen, &err);
|
||||
}
|
||||
ret = qio_channel_write(
|
||||
vs->ioc, (const char *)data, datalen, &err);
|
||||
VNC_DEBUG("Wrote wire %p %zd -> %ld\n", data, datalen, ret);
|
||||
return vnc_client_io_error(vs, ret, &err);
|
||||
}
|
||||
@ -1448,21 +1402,8 @@ ssize_t vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen)
|
||||
{
|
||||
ssize_t ret;
|
||||
Error *err = NULL;
|
||||
if (vs->tls) {
|
||||
ret = qcrypto_tls_session_read(vs->tls, (char *)data, datalen);
|
||||
if (ret < 0) {
|
||||
if (errno == EAGAIN) {
|
||||
ret = QIO_CHANNEL_ERR_BLOCK;
|
||||
} else {
|
||||
ret = -1;
|
||||
error_setg_errno(&err, errno, "%s",
|
||||
"Cannot read from TLS socket");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = qio_channel_read(
|
||||
vs->ioc, (char *)data, datalen, &err);
|
||||
}
|
||||
ret = qio_channel_read(
|
||||
vs->ioc, (char *)data, datalen, &err);
|
||||
VNC_DEBUG("Read wire %p %zd -> %ld\n", data, datalen, ret);
|
||||
return vnc_client_io_error(vs, ret, &err);
|
||||
}
|
||||
@ -3773,7 +3714,7 @@ void vnc_display_open(const char *id, Error **errp)
|
||||
vs->tlsaclname = g_strdup_printf("vnc.%s.x509dname", vs->id);
|
||||
}
|
||||
qemu_acl_init(vs->tlsaclname);
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_VNC_SASL
|
||||
if (acl && sasl) {
|
||||
char *aclname;
|
||||
|
5
ui/vnc.h
5
ui/vnc.h
@ -36,6 +36,7 @@
|
||||
#include "crypto/tlssession.h"
|
||||
#include "qemu/buffer.h"
|
||||
#include "io/channel-socket.h"
|
||||
#include "io/channel-tls.h"
|
||||
#include <zlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
@ -281,7 +282,7 @@ struct VncState
|
||||
int auth;
|
||||
int subauth; /* Used by VeNCrypt */
|
||||
char challenge[VNC_AUTH_CHALLENGE_SIZE];
|
||||
QCryptoTLSSession *tls;
|
||||
QCryptoTLSSession *tls; /* Borrowed pointer from channel, don't free */
|
||||
#ifdef CONFIG_VNC_SASL
|
||||
VncStateSASL sasl;
|
||||
#endif
|
||||
@ -511,8 +512,6 @@ gboolean vnc_client_io(QIOChannel *ioc,
|
||||
|
||||
ssize_t vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen);
|
||||
ssize_t vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen);
|
||||
ssize_t vnc_tls_pull(char *buf, size_t len, void *opaque);
|
||||
ssize_t vnc_tls_push(const char *buf, size_t len, void *opaque);
|
||||
|
||||
/* Protocol I/O functions */
|
||||
void vnc_write(VncState *vs, const void *data, size_t len);
|
||||
|
Loading…
Reference in New Issue
Block a user