Having repeatedly said that we should be doing TLS encryption for VNC, I
figured I ought to get down & implement it. So, in the spirit of 'release
early, release often', here is the very first cut of my patch for QEMU.
This isn't suitable for inclusion in CVS yet - I just want to put it out
for people to see / experiment with.
- The event loop in vl.c does not handle removal of file descriptors
in a safe way, so if you remove a filedescriptor during a read
event, there is a pretty good chance the event loop will SEGV when
checking the write condition. The way I've got around this is that
in the qemu_set_fd_handler2() method, instead of removing the
IOHandlerRecord object from the list, we simply set the fd to -1.
In the main_loop_wait() method, when processing the results from
select() we skip over any fd's set to -1, and then have a 2nd
loop over the IOHandlerRecord records to finally remove any objects
whose fd is set to -1. This lets us safely remove filedescriptors
from within callbacks.
- The VNC code now negotiates any protocol version out of 3.3, 3.7, 3.8
- There is support for the current 'None' auth type, the standard 'VNC'
challenge/response auth type, and finally the VeNCrypt extension which
implements a TLS layer with several sub-auth types. Since it can now
do any protocol version, and negotiate auth types, we should be able
to easily add more auth types if we want compatability with other
RFB auth extensions from projects like UltraVNC/TightVNC/etc.
- When choosing the VeNCrypt auth type, the client/server then negotiate
which sub-auth type they want to use. Then they perform a standard
TLS handshake, and if this is successful move on to do the actual
authentication. So the actual auth data exchange, and all subsequent
RFB protocol traffic is TLS encrypted.
- The sub-auth types supported by VeNCrypt are:
- Plain - username & password - no TLS at all
- TLS Anon + None - TLS anonymous credential exchange, followed
by standard 'None' auth type.
- TLS Anon + VNC - TLS anonymous credential exchange, followed
by standard 'VNC' auth type.
- TLS Anon + Plain - TLS anonymous credential exchange, followed
by customer 'Plain' username/password auth type.
- TLS X509 + None - TLS x509 cert credential exchange, followed
by standard 'None' auth type.
- TLS X509 + VNC - TLS x509 cert credential exchange, followed
by standard 'VNC' auth type.
- TLS X509 + Plain - TLS x509 cert credential exchange, followed
by customer 'Plain' username/password auth type.
- I did not implement any of the 'Plain' sub-auth types above. I may
add the TLS encrtyped Plain auth types, but certainly not the clear
text version.
- The 3 TLS Anon subauth types use the basic diffie-hellman anonymous
credential exchange. Since there is no apriori trust relationship,
this is subject to MITM attacks, so only marginally more useful than
the existing clear text wire format.
- The 3 TLS x509 subauth types do a full x509 certificate exchange.
This is exactly the same top security model as used in the most
recent HTTPS protocol implementationss, so the mode I'd recommend.
The server needs to be configured with a CA cert, a CA revocation
list (to block revoked clients), and its own server cert & key.
The server is currently setup to request a client cert and will
verify the cert against the CA cert & CRL. I need to make it
possible to turn this client cert verification on/off. If you used
TLS X509 + None, then a whitelist of client CNAMEs and client
cert verification could be your primary auth. If you use the TLS
X509 + VNC / Plain auth schemes, then client cert verification
should be optional. So client programs connecting at very least
need access to the CA Cert, and if the server does cert verification
client programs will need to supply their own certificate too.
- Currently I've just hardcode which auth scheme the server will
activate in vnc_display_init() method - this is one of the reasons
the patch isn't ready to commit to CVS yet. I need to tie in the
auth setup into either extra command line args, or extra monitor
commands (or probably a mix of both). eg I need to hook up Anthony
Ligouri's monitor command for changing the password to this.
I also need to figure out to best specify the paths to the server
key/key and CA cert/ CRL files. Currently they're hardcoded to
be in the files cert.pem, key.pem, ca-cert.pem ca-crl.pem in
the current working directory.
- I hardcoded the makefile to call pkg-config to determine gnutls
compiler/linker flags. This obviously needs to be fixed to be
done in the regular configure script. Also all the TLS support
needs to be #ifdef HAVE_TLS so