qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH 3/3] ui: fix VNC websockets TLS integration


From: Alex Bennée
Subject: Re: [Qemu-devel] [PATCH 3/3] ui: fix VNC websockets TLS integration
Date: Mon, 16 Mar 2015 13:17:16 +0000

Daniel P. Berrange <address@hidden> writes:

> The way the websockets TLS code was integrated into the VNC server
> made it insecure and essentially useless. The only time that the
> websockets TLS support could be used is if the primary VNC server
<snip>
>
> With this patch applied a number of things change
>
>  - TLS is not activated for websockets unless the 'tls' flag is
>    actually given.
>  - Non-TLS websockets connections are dropped if TLS is active
>  - The client certificate is validated after handshake completes
>    if the 'x509verify' flag is given
>  - Separate VNC auth scheme is tracked for websockets server,
>    since it makes no sense to try to use VeNCrypt over a TLS
>    enabled websockets connection.
>  - The separate "VncDisplayTLS ws_tls" field is dropped, since
>    the auth setup ensures we can never have multiple TLS sessions.

I wonder if the mechanical changes to the tls field could be separated
from the logic changes to the handling of authentication and certificate
checking?

> @@ -422,13 +417,6 @@ void vnc_tls_client_cleanup(struct VncState *vs)
>          vs->tls.session = NULL;
>      }
>      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;
> -    }
> -    g_free(vs->ws_tls.dname);
> -#endif /* CONFIG_VNC_WS */

I get we have added a bunch of exit cases earlier on that clean-up but
what happens when we do a clean shutdown? Have we just leaked?

Perhaps the tls.session cleanup code should be in a shared function?

>  }
>  
>  
> diff --git a/ui/vnc-ws.c b/ui/vnc-ws.c
> index 1769d52..5f9fcc4 100644
> --- a/ui/vnc-ws.c
> +++ b/ui/vnc-ws.c
> @@ -24,16 +24,14 @@
>  #ifdef CONFIG_VNC_TLS
>  #include "qemu/sockets.h"
>  
> -static void vncws_tls_handshake_io(void *opaque);
> -
>  static int vncws_start_tls_handshake(struct VncState *vs)
>  {
> -    int ret = gnutls_handshake(vs->ws_tls.session);
> +    int ret = gnutls_handshake(vs->tls.session);
>  
>      if (ret < 0) {
>          if (!gnutls_error_is_fatal(ret)) {
>              VNC_DEBUG("Handshake interrupted (blocking)\n");
> -            if (!gnutls_record_get_direction(vs->ws_tls.session)) {
> +            if (!gnutls_record_get_direction(vs->tls.session)) {
>                  qemu_set_fd_handler(vs->csock, vncws_tls_handshake_io,
>                                      NULL, vs);
>              } else {
> @@ -53,33 +51,18 @@ static int vncws_start_tls_handshake(struct VncState *vs)
>      return 0;
>  }
>  
> -static void vncws_tls_handshake_io(void *opaque)
> +void vncws_tls_handshake_io(void *opaque)
>  {
>      struct VncState *vs = (struct VncState *)opaque;
>  
> -    VNC_DEBUG("Handshake IO continue\n");
> -    vncws_start_tls_handshake(vs);
> -}
> -
> -void vncws_tls_handshake_peek(void *opaque)
> -{
> -    VncState *vs = opaque;
> -    long ret;
> -
> -    if (!vs->ws_tls.session) {
> -        char peek[4];
> -        ret = qemu_recv(vs->csock, peek, sizeof(peek), MSG_PEEK);
> -        if (ret && (strncmp(peek, "\x16", 1) == 0
> -                    || strncmp(peek, "\x80", 1) == 0)) {
> -            VNC_DEBUG("TLS Websocket connection recognized");
> -            vnc_tls_client_setup(vs, 1);
> -            vncws_start_tls_handshake(vs);
> -        } else {
> -            vncws_handshake_read(vs);
> +    if (!vs->tls.session) {
> +        VNC_DEBUG("TLS Websocket setup\n");
> +        if (vnc_tls_client_setup(vs, vs->vd->tls.x509cert != NULL) < 0) {
> +            return;
>          }
> -    } else {
> -        qemu_set_fd_handler2(vs->csock, NULL, vncws_handshake_read, NULL, 
> vs);
>      }
> +    VNC_DEBUG("Handshake IO continue\n");
> +    vncws_start_tls_handshake(vs);
>  }
>  #endif /* CONFIG_VNC_TLS */
>  
> diff --git a/ui/vnc-ws.h b/ui/vnc-ws.h
> index 95c1b0a..ef229b7 100644
> --- a/ui/vnc-ws.h
> +++ b/ui/vnc-ws.h
> @@ -75,7 +75,7 @@ enum {
>  };
>  
>  #ifdef CONFIG_VNC_TLS
> -void vncws_tls_handshake_peek(void *opaque);
> +void vncws_tls_handshake_io(void *opaque);
>  #endif /* CONFIG_VNC_TLS */
>  void vncws_handshake_read(void *opaque);
>  long vnc_client_write_ws(VncState *vs);
> diff --git a/ui/vnc.c b/ui/vnc.c
> index 80dc63b..90684f1 100644
> --- a/ui/vnc.c
> +++ b/ui/vnc.c
> @@ -1343,15 +1343,8 @@ long vnc_client_write_buf(VncState *vs, const uint8_t 
> *data, size_t datalen)
>      if (vs->tls.session) {
>          ret = vnc_client_write_tls(&vs->tls.session, data, datalen);
>      } else {
> -#ifdef CONFIG_VNC_WS
> -        if (vs->ws_tls.session) {
> -            ret = vnc_client_write_tls(&vs->ws_tls.session, data, datalen);
> -        } else
> -#endif /* CONFIG_VNC_WS */
>  #endif /* CONFIG_VNC_TLS */
> -        {
> -            ret = send(vs->csock, (const void *)data, datalen, 0);
> -        }
> +        ret = send(vs->csock, (const void *)data, datalen, 0);
>  #ifdef CONFIG_VNC_TLS
>      }
>  #endif /* CONFIG_VNC_TLS */
> @@ -1491,15 +1484,8 @@ long vnc_client_read_buf(VncState *vs, uint8_t *data, 
> size_t datalen)
>      if (vs->tls.session) {
>          ret = vnc_client_read_tls(&vs->tls.session, data, datalen);
>      } else {
> -#ifdef CONFIG_VNC_WS
> -        if (vs->ws_tls.session) {
> -            ret = vnc_client_read_tls(&vs->ws_tls.session, data, datalen);
> -        } else
> -#endif /* CONFIG_VNC_WS */
>  #endif /* CONFIG_VNC_TLS */
> -        {
> -            ret = qemu_recv(vs->csock, data, datalen, 0);
> -        }
> +        ret = qemu_recv(vs->csock, data, datalen, 0);
>  #ifdef CONFIG_VNC_TLS
>      }
>  #endif /* CONFIG_VNC_TLS */
> @@ -3014,11 +3000,29 @@ static void vnc_connect(VncDisplay *vd, int csock,
>       vs->subauth = VNC_AUTH_INVALID;
>  #endif
>      } else {
> -     vs->auth = vd->auth;
> +#ifdef CONFIG_VNC_WS
> +        if (websocket) {
> +            vs->auth = vd->ws_auth;
> +#ifdef CONFIG_VNC_TLS
> +            vs->subauth = VNC_AUTH_INVALID;
> +#endif
> +        } else {
> +#endif
> +            vs->auth = vd->auth;
>  #ifdef CONFIG_VNC_TLS
> -     vs->subauth = vd->subauth;
> +            vs->subauth = vd->subauth;
> +#endif
> +#ifdef CONFIG_VNC_WS
> +        }
>  #endif
>      }
> +#ifdef CONFIG_VNC_TLS
> +    VNC_DEBUG("Client sock=%d ws=%d auth=%d subauth=%d\n",
> +              csock, websocket, vs->auth, vs->subauth);
> +#else
> +    VNC_DEBUG("Client sock=%d ws=%d auth=%d\n",
> +              csock, websocket, vs->auth);
> +#endif
>  
>      vs->lossy_rect = g_malloc0(VNC_STAT_ROWS * sizeof (*vs->lossy_rect));
>      for (i = 0; i < VNC_STAT_ROWS; ++i) {
> @@ -3032,8 +3036,8 @@ static void vnc_connect(VncDisplay *vd, int csock,
>      if (websocket) {
>          vs->websocket = 1;
>  #ifdef CONFIG_VNC_TLS
> -        if (vd->tls.x509cert) {
> -            qemu_set_fd_handler2(vs->csock, NULL, vncws_tls_handshake_peek,
> +        if (vd->ws_tls) {
> +            qemu_set_fd_handler2(vs->csock, NULL, vncws_tls_handshake_io,
>                                   NULL, vs);
>          } else
>  #endif /* CONFIG_VNC_TLS */
> @@ -3577,6 +3581,24 @@ void vnc_display_open(const char *id, Error **errp)
>          }
>  #endif
>      }
> +#ifdef CONFIG_VNC_WS
> +    if (websocket) {
> +        if (password) {
> +            vs->ws_auth = VNC_AUTH_VNC;
> +#ifdef CONFIG_VNC_SASL
> +        } else if (sasl) {
> +            vs->ws_auth = VNC_AUTH_SASL;
> +#endif
> +        } else {
> +            vs->ws_auth = VNC_AUTH_NONE;
> +        }
> +#ifdef CONFIG_VNC_TLS
> +        if (tls) {
> +            vs->ws_tls = true;
> +        }
> +#endif
> +    }
> +#endif
>  
>  #ifdef CONFIG_VNC_SASL
>      if ((saslErr = sasl_server_init(NULL, "qemu")) != SASL_OK) {
> diff --git a/ui/vnc.h b/ui/vnc.h
> index 66a0298..fc4ac9e 100644
> --- a/ui/vnc.h
> +++ b/ui/vnc.h
> @@ -180,6 +180,12 @@ struct VncDisplay
>      char *password;
>      time_t expires;
>      int auth;
> +#ifdef CONFIG_VNC_WS
> +    int ws_auth;
> +#ifdef CONFIG_VNC_TLS
> +    bool ws_tls;
> +#endif
> +#endif
>      bool lossy;
>      bool non_adaptive;
>  #ifdef CONFIG_VNC_TLS
> @@ -293,9 +299,6 @@ struct VncState
>      VncStateSASL sasl;
>  #endif
>  #ifdef CONFIG_VNC_WS
> -#ifdef CONFIG_VNC_TLS
> -    VncStateTLS ws_tls;
> -#endif /* CONFIG_VNC_TLS */
>      bool encode_ws;
>      bool websocket;
>  #endif /* CONFIG_VNC_WS */

-- 
Alex Bennée



reply via email to

[Prev in Thread] Current Thread [Next in Thread]