Daniel P. Berrange
2007-Oct-29 21:48 UTC
[Xen-devel] PATCH: 0/4: TLS encryption and x509 authentication for VNC
The following series of patches sync the VNC authentication support in Xen''s fork of QEMU, to match the latest upstream QEMU. This is to enable the new VeNCrypt protocol extension which provides for TLS enryption and x509 auth in the VNC server. This extension can be used by client programs such as the GTK-VNC widget[1], virt-viewer/virt-manager[2], and the VeNCrypt viewer[3] Since these patches are already upstream, they will go away next time we re-base QEMU in Xen, and thus have minimal long term maintainence pain, compared to current auth code which is not upstream. Regards, Dan. [1] http://gtk-vnc.sourceforge.net [2] http://virt-manager.org/ [3] http://sourceforge.net/projects/vencrypt/ -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel P. Berrange
2007-Oct-29 21:51 UTC
Re: [Xen-devel] PATCH: 1/4: QEMU event handler bug fix
This patch pulls in an upstream QEMU fix for dealing with a problem in the event dispatcher where a write callback gets unregistered while a write event is pending from poll. WIthout this the QEMU process with deference a NULL pointer & crash Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Dan. diff -rup xen-3.1.0-src.orig/tools/ioemu/vl.c xen-3.1.0-src.new/tools/ioemu/vl.c --- xen-3.1.0-src.orig/tools/ioemu/vl.c 2007-08-28 16:43:11.000000000 -0400 +++ xen-3.1.0-src.new/tools/ioemu/vl.c 2007-08-28 16:43:50.000000000 -0400 @@ -5217,12 +5217,10 @@ void main_loop_wait(int timeout) IOHandlerRecord **pioh; for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) { - if (ioh->deleted) - continue; - if (ioh->fd_read && FD_ISSET(ioh->fd, &rfds)) { + if (!ioh->deleted && ioh->fd_read && FD_ISSET(ioh->fd, &rfds)) { ioh->fd_read(ioh->opaque); } - if (ioh->fd_write && FD_ISSET(ioh->fd, &wfds)) { + if (!ioh->deleted && ioh->fd_write && FD_ISSET(ioh->fd, &wfds)) { ioh->fd_write(ioh->opaque); } } -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel P. Berrange
2007-Oct-29 21:51 UTC
Re: [Xen-devel] PATCH: 2/4: Revert current VNC auth support
This patch reverts the current Xen specific implementation of VNC authentication from the QEMU code. This is basically reverting 11840:02506a744315. The idea here is to get the VNC code back to more closely match upstream QEMU, before applying the upstream auth patches. Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Dan diff -rupN xen-unstable.hg-16125.orig/tools/ioemu/d3des.c xen-unstable.hg-16125.new/tools/ioemu/d3des.c --- xen-unstable.hg-16125.orig/tools/ioemu/d3des.c 2007-10-19 09:51:31.000000000 -0400 +++ xen-unstable.hg-16125.new/tools/ioemu/d3des.c 1969-12-31 19:00:00.000000000 -0500 @@ -1,434 +0,0 @@ -/* - * This is D3DES (V5.09) by Richard Outerbridge with the double and - * triple-length support removed for use in VNC. Also the bytebit[] array - * has been reversed so that the most significant bit in each byte of the - * key is ignored, not the least significant. - * - * These changes are: - * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -/* D3DES (V5.09) - - * - * A portable, public domain, version of the Data Encryption Standard. - * - * Written with Symantec''s THINK (Lightspeed) C by Richard Outerbridge. - * Thanks to: Dan Hoey for his excellent Initial and Inverse permutation - * code; Jim Gillogly & Phil Karn for the DES key schedule code; Dennis - * Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau, - * for humouring me on. - * - * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge. - * (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992. - */ - -#include "d3des.h" - -static void scrunch(unsigned char *, unsigned long *); -static void unscrun(unsigned long *, unsigned char *); -static void desfunc(unsigned long *, unsigned long *); -static void cookey(unsigned long *); - -static unsigned long KnL[32] = { 0L }; - -static unsigned short bytebit[8] = { - 01, 02, 04, 010, 020, 040, 0100, 0200 }; - -static unsigned long bigbyte[24] = { - 0x800000L, 0x400000L, 0x200000L, 0x100000L, - 0x80000L, 0x40000L, 0x20000L, 0x10000L, - 0x8000L, 0x4000L, 0x2000L, 0x1000L, - 0x800L, 0x400L, 0x200L, 0x100L, - 0x80L, 0x40L, 0x20L, 0x10L, - 0x8L, 0x4L, 0x2L, 0x1L }; - -/* Use the key schedule specified in the Standard (ANSI X3.92-1981). */ - -static unsigned char pc1[56] = { - 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17, - 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, - 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, - 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3 }; - -static unsigned char totrot[16] = { - 1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28 }; - -static unsigned char pc2[48] = { - 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, - 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1, - 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47, - 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 }; - -void deskey(key, edf) /* Thanks to James Gillogly & Phil Karn! */ -unsigned char *key; -int edf; -{ - register int i, j, l, m, n; - unsigned char pc1m[56], pcr[56]; - unsigned long kn[32]; - - for ( j = 0; j < 56; j++ ) { - l = pc1[j]; - m = l & 07; - pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0; - } - for( i = 0; i < 16; i++ ) { - if( edf == DE1 ) m = (15 - i) << 1; - else m = i << 1; - n = m + 1; - kn[m] = kn[n] = 0L; - for( j = 0; j < 28; j++ ) { - l = j + totrot[i]; - if( l < 28 ) pcr[j] = pc1m[l]; - else pcr[j] = pc1m[l - 28]; - } - for( j = 28; j < 56; j++ ) { - l = j + totrot[i]; - if( l < 56 ) pcr[j] = pc1m[l]; - else pcr[j] = pc1m[l - 28]; - } - for( j = 0; j < 24; j++ ) { - if( pcr[pc2[j]] ) kn[m] |= bigbyte[j]; - if( pcr[pc2[j+24]] ) kn[n] |= bigbyte[j]; - } - } - cookey(kn); - return; - } - -static void cookey(raw1) -register unsigned long *raw1; -{ - register unsigned long *cook, *raw0; - unsigned long dough[32]; - register int i; - - cook = dough; - for( i = 0; i < 16; i++, raw1++ ) { - raw0 = raw1++; - *cook = (*raw0 & 0x00fc0000L) << 6; - *cook |= (*raw0 & 0x00000fc0L) << 10; - *cook |= (*raw1 & 0x00fc0000L) >> 10; - *cook++ |= (*raw1 & 0x00000fc0L) >> 6; - *cook = (*raw0 & 0x0003f000L) << 12; - *cook |= (*raw0 & 0x0000003fL) << 16; - *cook |= (*raw1 & 0x0003f000L) >> 4; - *cook++ |= (*raw1 & 0x0000003fL); - } - usekey(dough); - return; - } - -void cpkey(into) -register unsigned long *into; -{ - register unsigned long *from, *endp; - - from = KnL, endp = &KnL[32]; - while( from < endp ) *into++ = *from++; - return; - } - -void usekey(from) -register unsigned long *from; -{ - register unsigned long *to, *endp; - - to = KnL, endp = &KnL[32]; - while( to < endp ) *to++ = *from++; - return; - } - -void des(inblock, outblock) -unsigned char *inblock, *outblock; -{ - unsigned long work[2]; - - scrunch(inblock, work); - desfunc(work, KnL); - unscrun(work, outblock); - return; - } - -static void scrunch(outof, into) -register unsigned char *outof; -register unsigned long *into; -{ - *into = (*outof++ & 0xffL) << 24; - *into |= (*outof++ & 0xffL) << 16; - *into |= (*outof++ & 0xffL) << 8; - *into++ |= (*outof++ & 0xffL); - *into = (*outof++ & 0xffL) << 24; - *into |= (*outof++ & 0xffL) << 16; - *into |= (*outof++ & 0xffL) << 8; - *into |= (*outof & 0xffL); - return; - } - -static void unscrun(outof, into) -register unsigned long *outof; -register unsigned char *into; -{ - *into++ = (unsigned char)((*outof >> 24) & 0xffL); - *into++ = (unsigned char)((*outof >> 16) & 0xffL); - *into++ = (unsigned char)((*outof >> 8) & 0xffL); - *into++ = (unsigned char)(*outof++ & 0xffL); - *into++ = (unsigned char)((*outof >> 24) & 0xffL); - *into++ = (unsigned char)((*outof >> 16) & 0xffL); - *into++ = (unsigned char)((*outof >> 8) & 0xffL); - *into = (unsigned char)(*outof & 0xffL); - return; - } - -static unsigned long SP1[64] = { - 0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L, - 0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L, - 0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L, - 0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L, - 0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L, - 0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L, - 0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L, - 0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L, - 0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L, - 0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L, - 0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L, - 0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L, - 0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L, - 0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L, - 0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L, - 0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L }; - -static unsigned long SP2[64] = { - 0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L, - 0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L, - 0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L, - 0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L, - 0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L, - 0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L, - 0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L, - 0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L, - 0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L, - 0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L, - 0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L, - 0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L, - 0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L, - 0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L, - 0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L, - 0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L }; - -static unsigned long SP3[64] = { - 0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L, - 0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L, - 0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L, - 0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L, - 0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L, - 0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L, - 0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L, - 0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L, - 0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L, - 0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L, - 0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L, - 0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L, - 0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L, - 0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L, - 0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L, - 0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L }; - -static unsigned long SP4[64] = { - 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L, - 0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L, - 0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L, - 0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L, - 0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L, - 0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L, - 0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L, - 0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L, - 0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L, - 0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L, - 0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L, - 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L, - 0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L, - 0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L, - 0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L, - 0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L }; - -static unsigned long SP5[64] = { - 0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L, - 0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L, - 0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L, - 0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L, - 0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L, - 0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L, - 0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L, - 0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L, - 0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L, - 0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L, - 0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L, - 0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L, - 0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L, - 0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L, - 0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L, - 0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L }; - -static unsigned long SP6[64] = { - 0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L, - 0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L, - 0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L, - 0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L, - 0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L, - 0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L, - 0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L, - 0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L, - 0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L, - 0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L, - 0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L, - 0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L, - 0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L, - 0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L, - 0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L, - 0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L }; - -static unsigned long SP7[64] = { - 0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L, - 0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L, - 0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L, - 0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L, - 0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L, - 0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L, - 0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L, - 0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L, - 0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L, - 0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L, - 0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L, - 0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L, - 0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L, - 0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L, - 0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L, - 0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L }; - -static unsigned long SP8[64] = { - 0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L, - 0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L, - 0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L, - 0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L, - 0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L, - 0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L, - 0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L, - 0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L, - 0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L, - 0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L, - 0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L, - 0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L, - 0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L, - 0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L, - 0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L, - 0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L }; - -static void desfunc(block, keys) -register unsigned long *block, *keys; -{ - register unsigned long fval, work, right, leftt; - register int round; - - leftt = block[0]; - right = block[1]; - work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL; - right ^= work; - leftt ^= (work << 4); - work = ((leftt >> 16) ^ right) & 0x0000ffffL; - right ^= work; - leftt ^= (work << 16); - work = ((right >> 2) ^ leftt) & 0x33333333L; - leftt ^= work; - right ^= (work << 2); - work = ((right >> 8) ^ leftt) & 0x00ff00ffL; - leftt ^= work; - right ^= (work << 8); - right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL; - work = (leftt ^ right) & 0xaaaaaaaaL; - leftt ^= work; - right ^= work; - leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL; - - for( round = 0; round < 8; round++ ) { - work = (right << 28) | (right >> 4); - work ^= *keys++; - fval = SP7[ work & 0x3fL]; - fval |= SP5[(work >> 8) & 0x3fL]; - fval |= SP3[(work >> 16) & 0x3fL]; - fval |= SP1[(work >> 24) & 0x3fL]; - work = right ^ *keys++; - fval |= SP8[ work & 0x3fL]; - fval |= SP6[(work >> 8) & 0x3fL]; - fval |= SP4[(work >> 16) & 0x3fL]; - fval |= SP2[(work >> 24) & 0x3fL]; - leftt ^= fval; - work = (leftt << 28) | (leftt >> 4); - work ^= *keys++; - fval = SP7[ work & 0x3fL]; - fval |= SP5[(work >> 8) & 0x3fL]; - fval |= SP3[(work >> 16) & 0x3fL]; - fval |= SP1[(work >> 24) & 0x3fL]; - work = leftt ^ *keys++; - fval |= SP8[ work & 0x3fL]; - fval |= SP6[(work >> 8) & 0x3fL]; - fval |= SP4[(work >> 16) & 0x3fL]; - fval |= SP2[(work >> 24) & 0x3fL]; - right ^= fval; - } - - right = (right << 31) | (right >> 1); - work = (leftt ^ right) & 0xaaaaaaaaL; - leftt ^= work; - right ^= work; - leftt = (leftt << 31) | (leftt >> 1); - work = ((leftt >> 8) ^ right) & 0x00ff00ffL; - right ^= work; - leftt ^= (work << 8); - work = ((leftt >> 2) ^ right) & 0x33333333L; - right ^= work; - leftt ^= (work << 2); - work = ((right >> 16) ^ leftt) & 0x0000ffffL; - leftt ^= work; - right ^= (work << 16); - work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL; - leftt ^= work; - right ^= (work << 4); - *block++ = right; - *block = leftt; - return; - } - -/* Validation sets: - * - * Single-length key, single-length plaintext - - * Key : 0123 4567 89ab cdef - * Plain : 0123 4567 89ab cde7 - * Cipher : c957 4425 6a5e d31d - * - * Double-length key, single-length plaintext - - * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 - * Plain : 0123 4567 89ab cde7 - * Cipher : 7f1d 0a77 826b 8aff - * - * Double-length key, double-length plaintext - - * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 - * Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff - * Cipher : 27a0 8440 406a df60 278f 47cf 42d6 15d7 - * - * Triple-length key, single-length plaintext - - * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567 - * Plain : 0123 4567 89ab cde7 - * Cipher : de0b 7c06 ae5e 0ed5 - * - * Triple-length key, double-length plaintext - - * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567 - * Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff - * Cipher : ad0d 1b30 ac17 cf07 0ed1 1c63 81e4 4de5 - * - * d3des V5.0a rwo 9208.07 18:44 Graven Imagery - **********************************************************************/ diff -rupN xen-unstable.hg-16125.orig/tools/ioemu/d3des.h xen-unstable.hg-16125.new/tools/ioemu/d3des.h --- xen-unstable.hg-16125.orig/tools/ioemu/d3des.h 2007-10-19 09:51:31.000000000 -0400 +++ xen-unstable.hg-16125.new/tools/ioemu/d3des.h 1969-12-31 19:00:00.000000000 -0500 @@ -1,51 +0,0 @@ -/* - * This is D3DES (V5.09) by Richard Outerbridge with the double and - * triple-length support removed for use in VNC. - * - * These changes are: - * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -/* d3des.h - - * - * Headers and defines for d3des.c - * Graven Imagery, 1992. - * - * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge - * (GEnie : OUTER; CIS : [71755,204]) - */ - -#define EN0 0 /* MODE == encrypt */ -#define DE1 1 /* MODE == decrypt */ - -extern void deskey(unsigned char *, int); -/* hexkey[8] MODE - * Sets the internal key register according to the hexadecimal - * key contained in the 8 bytes of hexkey, according to the DES, - * for encryption or decryption according to MODE. - */ - -extern void usekey(unsigned long *); -/* cookedkey[32] - * Loads the internal key register with the data in cookedkey. - */ - -extern void cpkey(unsigned long *); -/* cookedkey[32] - * Copies the contents of the internal key register into the storage - * located at &cookedkey[0]. - */ - -extern void des(unsigned char *, unsigned char *); -/* from[8] to[8] - * Encrypts/Decrypts (according to the key currently loaded in the - * internal key register) one block of eight bytes at address ''from'' - * into the block at address ''to''. They can be the same. - */ - -/* d3des.h V5.09 rwo 9208.04 15:06 Graven Imagery - ********************************************************************/ diff -rupN xen-unstable.hg-16125.orig/tools/ioemu/Makefile.target xen-unstable.hg-16125.new/tools/ioemu/Makefile.target --- xen-unstable.hg-16125.orig/tools/ioemu/Makefile.target 2007-10-29 15:38:10.000000000 -0400 +++ xen-unstable.hg-16125.new/tools/ioemu/Makefile.target 2007-10-29 15:39:32.000000000 -0400 @@ -457,7 +457,6 @@ ifdef CONFIG_SDL VL_OBJS+=sdl.o x_keymap.o endif VL_OBJS+=vnc.o -VL_OBJS+=d3des.o ifdef CONFIG_COCOA VL_OBJS+=cocoa.o COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa -framework IOKit @@ -518,9 +517,6 @@ sdl.o: sdl.c keymaps.c sdl_keysym.h vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< -d3des.o: d3des.c d3des.h - $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< - sdlaudio.o: sdlaudio.c $(CC) $(CFLAGS) $(CPPFLAGS) $(SDL_CFLAGS) $(BASE_CFLAGS) -c -o $@ $< diff -rupN xen-unstable.hg-16125.orig/tools/ioemu/vl.c xen-unstable.hg-16125.new/tools/ioemu/vl.c --- xen-unstable.hg-16125.orig/tools/ioemu/vl.c 2007-10-29 15:38:10.000000000 -0400 +++ xen-unstable.hg-16125.new/tools/ioemu/vl.c 2007-10-29 15:39:32.000000000 -0400 @@ -196,9 +196,6 @@ int xc_handle; char domain_name[64] = "Xen-no-name"; extern int domid; -char vncpasswd[64]; -unsigned char challenge[AUTHCHALLENGESIZE]; - /***********************************************************/ /* x86 ISA bus support */ @@ -7039,7 +7036,6 @@ int main(int argc, char **argv) vncunused = 0; kernel_filename = NULL; kernel_cmdline = ""; - *vncpasswd = ''\0''; #ifndef CONFIG_DM #ifdef TARGET_PPC cdrom_index = 1; @@ -7684,10 +7680,6 @@ int main(int argc, char **argv) init_ioports(); - /* read vncpasswd from xenstore */ - if (0 > xenstore_read_vncpasswd(domid)) - exit(1); - /* terminal init */ if (nographic) { dumb_display_init(ds); diff -rupN xen-unstable.hg-16125.orig/tools/ioemu/vl.h xen-unstable.hg-16125.new/tools/ioemu/vl.h --- xen-unstable.hg-16125.orig/tools/ioemu/vl.h 2007-10-29 15:38:10.000000000 -0400 +++ xen-unstable.hg-16125.new/tools/ioemu/vl.h 2007-10-29 15:40:00.000000000 -0400 @@ -1453,7 +1453,7 @@ void xenstore_process_event(void *opaque void xenstore_record_dm_state(char *state); void xenstore_check_new_media_present(int timeout); void xenstore_write_vncport(int vnc_display); -int xenstore_read_vncpasswd(int domid); +int xenstore_read_vncpasswd(int domid, char *pwbuf, size_t pwbuflen); int xenstore_domain_has_devtype(struct xs_handle *handle, const char *devtype); @@ -1490,9 +1490,6 @@ extern char domain_name[]; void destroy_hvm_domain(void); -/* VNC Authentication */ -#define AUTHCHALLENGESIZE 16 - #ifdef __ia64__ static inline void xc_domain_shutdown_hook(int xc_handle, uint32_t domid) { diff -rupN xen-unstable.hg-16125.orig/tools/ioemu/vnc.c xen-unstable.hg-16125.new/tools/ioemu/vnc.c --- xen-unstable.hg-16125.orig/tools/ioemu/vnc.c 2007-10-19 09:51:32.000000000 -0400 +++ xen-unstable.hg-16125.new/tools/ioemu/vnc.c 2007-10-29 15:39:32.000000000 -0400 @@ -47,7 +47,6 @@ #include "vnc_keysym.h" #include "keymaps.c" -#include "d3des.h" typedef struct Buffer { @@ -164,9 +163,6 @@ static void _vnc_update_client(void *opa static void vnc_update_client(void *opaque); static void vnc_client_read(void *opaque); static void framebuffer_set_updated(VncState *vs, int x, int y, int w, int h); -static int make_challenge(unsigned char *random, int size); -static void set_seed(unsigned int *seedp); -static void get_random(int len, unsigned char *buf); #if 0 static inline void vnc_set_bit(uint32_t *d, int k) @@ -1387,92 +1383,24 @@ static int protocol_client_init(VncState return 0; } -static int protocol_response(VncState *vs, uint8_t *client_response, size_t len) -{ - extern char vncpasswd[64]; - extern unsigned char challenge[AUTHCHALLENGESIZE]; - unsigned char cryptchallenge[AUTHCHALLENGESIZE]; - unsigned char key[8]; - int passwdlen, i, j; - - memcpy(cryptchallenge, challenge, AUTHCHALLENGESIZE); - - /* Calculate the sent challenge */ - passwdlen = strlen(vncpasswd); - for (i=0; i<8; i++) - key[i] = i<passwdlen ? vncpasswd[i] : 0; - deskey(key, EN0); - for (j = 0; j < AUTHCHALLENGESIZE; j += 8) - des(cryptchallenge+j, cryptchallenge+j); - - /* Check the actual response */ - if (memcmp(cryptchallenge, client_response, AUTHCHALLENGESIZE) != 0) { - /* password error */ - vnc_write_u32(vs, 1); - vnc_write_u32(vs, 22); - vnc_write(vs, "Authentication failure", 22); - vnc_flush(vs); - fprintf(stderr, "VNC Password error.\n"); - vnc_client_error(vs); - return 0; - } - - vnc_write_u32(vs, 0); - vnc_flush(vs); - - vnc_read_when(vs, protocol_client_init, 1); - - return 0; -} static int protocol_version(VncState *vs, uint8_t *version, size_t len) { - extern char vncpasswd[64]; - extern unsigned char challenge[AUTHCHALLENGESIZE]; char local[13]; - int support, maj, min; + int maj, min; memcpy(local, version, 12); local[12] = 0; - /* protocol version check */ if (sscanf(local, "RFB %03d.%03d\n", &maj, &min) != 2) { - fprintf(stderr, "Protocol version error.\n"); vnc_client_error(vs); return 0; } - - support = 0; - if (maj == 3) { - if (min == 3 || min ==4) { - support = 1; - } - } - - if (! support) { - fprintf(stderr, "Client uses unsupported protocol version %d.%d.\n", - maj, min); - vnc_client_error(vs); - return 0; - } - - if (*vncpasswd == ''\0'') { - /* AuthType is None */ - vnc_write_u32(vs, 1); - vnc_flush(vs); - vnc_read_when(vs, protocol_client_init, 1); - } else { - /* AuthType is VncAuth */ - vnc_write_u32(vs, 2); - - /* Challenge-Responce authentication */ - /* Send Challenge */ - make_challenge(challenge, AUTHCHALLENGESIZE); - vnc_write(vs, challenge, AUTHCHALLENGESIZE); - vnc_flush(vs); - vnc_read_when(vs, protocol_response, AUTHCHALLENGESIZE); - } + vnc_write_u32(vs, 1); /* None */ + vnc_flush(vs); + + vnc_read_when(vs, protocol_client_init, 1); return 0; } @@ -1640,31 +1568,3 @@ int vnc_start_viewer(int port) } } -unsigned int seed; - -static int make_challenge(unsigned char *random, int size) -{ - - set_seed(&seed); - get_random(size, random); - - return 0; -} - -static void set_seed(unsigned int *seedp) -{ - *seedp += (unsigned int)(time(NULL)+getpid()+getpid()*987654+rand()); - srand(*seedp); - - return; -} - -static void get_random(int len, unsigned char *buf) -{ - int i; - - for (i=0; i<len; i++) - buf[i] = (int) (256.0*rand()/(RAND_MAX+1.0)); - - return; -} diff -rupN xen-unstable.hg-16125.orig/tools/ioemu/xenstore.c xen-unstable.hg-16125.new/tools/ioemu/xenstore.c --- xen-unstable.hg-16125.orig/tools/ioemu/xenstore.c 2007-10-29 15:38:10.000000000 -0400 +++ xen-unstable.hg-16125.new/tools/ioemu/xenstore.c 2007-10-29 15:39:32.000000000 -0400 @@ -478,9 +478,8 @@ void xenstore_write_vncport(int display) free(buf); } -int xenstore_read_vncpasswd(int domid) +int xenstore_read_vncpasswd(int domid, char *pwbuf, size_t pwbuflen) { - extern char vncpasswd[64]; char *buf = NULL, *path, *uuid = NULL, *passwd = NULL; unsigned int i, len, rc = 0; @@ -511,11 +510,11 @@ int xenstore_read_vncpasswd(int domid) return rc; } - for (i=0; i<len && i<63; i++) { - vncpasswd[i] = passwd[i]; - passwd[i] = ''\0''; + for (i=0; i<len && i<pwbuflen; i++) { + pwbuf[i] = passwd[i]; } - vncpasswd[len] = ''\0''; + pwbuf[len < (pwbuflen-1) ? len : (pwbuflen-1)] = ''\0''; + passwd[0] = ''\0''; pasprintf(&buf, "%s/vncpasswd", uuid); if (xs_write(xsh, XBT_NULL, buf, passwd, len) == 0) { fprintf(logfile, "xs_write() vncpasswd failed.\n"); -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel P. Berrange
2007-Oct-29 21:52 UTC
Re: [Xen-devel] PATCH: 3/4: Add VNC auth support from upstream QEMU
This patch adds in the upstream QEMU VNC authentication code. This spports the previous VNC password auth scheme, as well as the VeNCrypt protocol extenion. The latter allows for performing a TLS handshake, and client verification of the server identify using x509 certificates. It is also possible for the server to request a client certificate and validate that as a simple auth scheme. The code depends on GNU TLS for SSL APIs, and the configure script will auto-detect this. The image.py code is changed to deal with thenew syntax for the -vnc option. In particular password authentication is now enabled by giving the ''password'' flag, eg -vnc 0.0.0:1,password Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Dan. diff -rupN xen-unstable.hg-16125.orig/tools/ioemu/configure xen-unstable.hg-16125.new/tools/ioemu/configure --- xen-unstable.hg-16125.orig/tools/ioemu/configure 2007-10-19 09:51:31.000000000 -0400 +++ xen-unstable.hg-16125.new/tools/ioemu/configure 2007-10-29 16:45:01.000000000 -0400 @@ -87,6 +87,7 @@ alsa="no" fmod="no" fmod_lib="" fmod_inc="" +vnc_tls="yes" bsd="no" linux="no" kqemu="no" @@ -225,6 +226,8 @@ for opt do ;; --fmod-inc=*) fmod_inc="$optarg" ;; + --disable-vnc-tls) vnc_tls="no" + ;; --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" ; user="no" ;; --disable-slirp) slirp="no" @@ -292,6 +295,7 @@ echo " --enable-coreaudio enable echo " --enable-alsa enable ALSA audio driver" echo " --enable-fmod enable FMOD audio driver" echo " --enabled-dsound enable DirectSound audio driver" +echo " --disable-vnc-tls disable TLS encryption for VNC server" echo " --enable-system enable all system emulation targets" echo " --disable-system disable all system emulation targets" echo " --enable-linux-user enable all linux usermode emulation targets" @@ -410,6 +414,18 @@ if test "$solaris" = "yes" ; then fi fi +########################################## + +# VNC TLS detection +if test "$vnc_tls" = "yes" ; then + `pkg-config gnutls` || vnc_tls="no" +fi +if test "$vnc_tls" = "yes" ; then + vnc_tls_cflags=`pkg-config --cflags gnutls` + vnc_tls_libs=`pkg-config --libs gnutls` +fi + +########################################## if test -z "$target_list" ; then # these targets are portable @@ -772,6 +788,12 @@ if test "$fmod" = "yes" ; then echo "CONFIG_FMOD_INC=$fmod_inc" >> $config_mak echo "#define CONFIG_FMOD 1" >> $config_h fi +if test "$vnc_tls" = "yes" ; then + echo "CONFIG_VNC_TLS=yes" >> $config_mak + echo "CONFIG_VNC_TLS_CFLAGS=$vnc_tls_cflags" >> $config_mak + echo "CONFIG_VNC_TLS_LIBS=$vnc_tls_libs" >> $config_mak + echo "#define CONFIG_VNC_TLS 1" >> $config_h +fi qemu_version=`head $source_path/VERSION` echo "VERSION=$qemu_version" >>$config_mak echo "#define QEMU_VERSION \"$qemu_version\"" >> $config_h @@ -999,4 +1021,10 @@ if test "$source_path_used" = "yes" ; th done fi +echo "VNC TLS support $vnc_tls" +if test "$vnc_tls" = "yes" ; then + echo " TLS CFLAGS $vnc_tls_cflags" + echo " TLS LIBS $vnc_tls_libs" +fi + rm -f $TMPO $TMPC $TMPE $TMPS diff -rupN xen-unstable.hg-16125.orig/tools/ioemu/d3des.c xen-unstable.hg-16125.new/tools/ioemu/d3des.c --- xen-unstable.hg-16125.orig/tools/ioemu/d3des.c 1969-12-31 19:00:00.000000000 -0500 +++ xen-unstable.hg-16125.new/tools/ioemu/d3des.c 2007-10-29 16:45:01.000000000 -0400 @@ -0,0 +1,434 @@ +/* + * This is D3DES (V5.09) by Richard Outerbridge with the double and + * triple-length support removed for use in VNC. Also the bytebit[] array + * has been reversed so that the most significant bit in each byte of the + * key is ignored, not the least significant. + * + * These changes are: + * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* D3DES (V5.09) - + * + * A portable, public domain, version of the Data Encryption Standard. + * + * Written with Symantec''s THINK (Lightspeed) C by Richard Outerbridge. + * Thanks to: Dan Hoey for his excellent Initial and Inverse permutation + * code; Jim Gillogly & Phil Karn for the DES key schedule code; Dennis + * Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau, + * for humouring me on. + * + * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge. + * (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992. + */ + +#include "d3des.h" + +static void scrunch(unsigned char *, unsigned long *); +static void unscrun(unsigned long *, unsigned char *); +static void desfunc(unsigned long *, unsigned long *); +static void cookey(unsigned long *); + +static unsigned long KnL[32] = { 0L }; + +static unsigned short bytebit[8] = { + 01, 02, 04, 010, 020, 040, 0100, 0200 }; + +static unsigned long bigbyte[24] = { + 0x800000L, 0x400000L, 0x200000L, 0x100000L, + 0x80000L, 0x40000L, 0x20000L, 0x10000L, + 0x8000L, 0x4000L, 0x2000L, 0x1000L, + 0x800L, 0x400L, 0x200L, 0x100L, + 0x80L, 0x40L, 0x20L, 0x10L, + 0x8L, 0x4L, 0x2L, 0x1L }; + +/* Use the key schedule specified in the Standard (ANSI X3.92-1981). */ + +static unsigned char pc1[56] = { + 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17, + 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, + 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, + 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3 }; + +static unsigned char totrot[16] = { + 1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28 }; + +static unsigned char pc2[48] = { + 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, + 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1, + 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47, + 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 }; + +void deskey(key, edf) /* Thanks to James Gillogly & Phil Karn! */ +unsigned char *key; +int edf; +{ + register int i, j, l, m, n; + unsigned char pc1m[56], pcr[56]; + unsigned long kn[32]; + + for ( j = 0; j < 56; j++ ) { + l = pc1[j]; + m = l & 07; + pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0; + } + for( i = 0; i < 16; i++ ) { + if( edf == DE1 ) m = (15 - i) << 1; + else m = i << 1; + n = m + 1; + kn[m] = kn[n] = 0L; + for( j = 0; j < 28; j++ ) { + l = j + totrot[i]; + if( l < 28 ) pcr[j] = pc1m[l]; + else pcr[j] = pc1m[l - 28]; + } + for( j = 28; j < 56; j++ ) { + l = j + totrot[i]; + if( l < 56 ) pcr[j] = pc1m[l]; + else pcr[j] = pc1m[l - 28]; + } + for( j = 0; j < 24; j++ ) { + if( pcr[pc2[j]] ) kn[m] |= bigbyte[j]; + if( pcr[pc2[j+24]] ) kn[n] |= bigbyte[j]; + } + } + cookey(kn); + return; + } + +static void cookey(raw1) +register unsigned long *raw1; +{ + register unsigned long *cook, *raw0; + unsigned long dough[32]; + register int i; + + cook = dough; + for( i = 0; i < 16; i++, raw1++ ) { + raw0 = raw1++; + *cook = (*raw0 & 0x00fc0000L) << 6; + *cook |= (*raw0 & 0x00000fc0L) << 10; + *cook |= (*raw1 & 0x00fc0000L) >> 10; + *cook++ |= (*raw1 & 0x00000fc0L) >> 6; + *cook = (*raw0 & 0x0003f000L) << 12; + *cook |= (*raw0 & 0x0000003fL) << 16; + *cook |= (*raw1 & 0x0003f000L) >> 4; + *cook++ |= (*raw1 & 0x0000003fL); + } + usekey(dough); + return; + } + +void cpkey(into) +register unsigned long *into; +{ + register unsigned long *from, *endp; + + from = KnL, endp = &KnL[32]; + while( from < endp ) *into++ = *from++; + return; + } + +void usekey(from) +register unsigned long *from; +{ + register unsigned long *to, *endp; + + to = KnL, endp = &KnL[32]; + while( to < endp ) *to++ = *from++; + return; + } + +void des(inblock, outblock) +unsigned char *inblock, *outblock; +{ + unsigned long work[2]; + + scrunch(inblock, work); + desfunc(work, KnL); + unscrun(work, outblock); + return; + } + +static void scrunch(outof, into) +register unsigned char *outof; +register unsigned long *into; +{ + *into = (*outof++ & 0xffL) << 24; + *into |= (*outof++ & 0xffL) << 16; + *into |= (*outof++ & 0xffL) << 8; + *into++ |= (*outof++ & 0xffL); + *into = (*outof++ & 0xffL) << 24; + *into |= (*outof++ & 0xffL) << 16; + *into |= (*outof++ & 0xffL) << 8; + *into |= (*outof & 0xffL); + return; + } + +static void unscrun(outof, into) +register unsigned long *outof; +register unsigned char *into; +{ + *into++ = (unsigned char)((*outof >> 24) & 0xffL); + *into++ = (unsigned char)((*outof >> 16) & 0xffL); + *into++ = (unsigned char)((*outof >> 8) & 0xffL); + *into++ = (unsigned char)(*outof++ & 0xffL); + *into++ = (unsigned char)((*outof >> 24) & 0xffL); + *into++ = (unsigned char)((*outof >> 16) & 0xffL); + *into++ = (unsigned char)((*outof >> 8) & 0xffL); + *into = (unsigned char)(*outof & 0xffL); + return; + } + +static unsigned long SP1[64] = { + 0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L, + 0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L, + 0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L, + 0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L, + 0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L, + 0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L, + 0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L, + 0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L, + 0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L, + 0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L, + 0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L, + 0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L, + 0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L, + 0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L, + 0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L, + 0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L }; + +static unsigned long SP2[64] = { + 0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L, + 0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L, + 0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L, + 0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L, + 0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L, + 0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L, + 0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L, + 0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L, + 0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L, + 0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L, + 0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L, + 0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L, + 0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L, + 0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L, + 0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L, + 0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L }; + +static unsigned long SP3[64] = { + 0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L, + 0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L, + 0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L, + 0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L, + 0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L, + 0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L, + 0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L, + 0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L, + 0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L, + 0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L, + 0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L, + 0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L, + 0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L, + 0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L, + 0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L, + 0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L }; + +static unsigned long SP4[64] = { + 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L, + 0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L, + 0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L, + 0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L, + 0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L, + 0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L, + 0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L, + 0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L, + 0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L, + 0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L, + 0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L, + 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L, + 0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L, + 0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L, + 0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L, + 0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L }; + +static unsigned long SP5[64] = { + 0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L, + 0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L, + 0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L, + 0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L, + 0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L, + 0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L, + 0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L, + 0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L, + 0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L, + 0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L, + 0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L, + 0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L, + 0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L, + 0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L, + 0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L, + 0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L }; + +static unsigned long SP6[64] = { + 0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L, + 0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L, + 0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L, + 0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L, + 0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L, + 0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L, + 0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L, + 0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L, + 0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L, + 0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L, + 0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L, + 0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L, + 0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L, + 0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L, + 0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L, + 0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L }; + +static unsigned long SP7[64] = { + 0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L, + 0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L, + 0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L, + 0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L, + 0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L, + 0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L, + 0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L, + 0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L, + 0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L, + 0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L, + 0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L, + 0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L, + 0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L, + 0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L, + 0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L, + 0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L }; + +static unsigned long SP8[64] = { + 0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L, + 0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L, + 0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L, + 0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L, + 0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L, + 0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L, + 0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L, + 0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L, + 0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L, + 0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L, + 0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L, + 0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L, + 0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L, + 0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L, + 0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L, + 0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L }; + +static void desfunc(block, keys) +register unsigned long *block, *keys; +{ + register unsigned long fval, work, right, leftt; + register int round; + + leftt = block[0]; + right = block[1]; + work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL; + right ^= work; + leftt ^= (work << 4); + work = ((leftt >> 16) ^ right) & 0x0000ffffL; + right ^= work; + leftt ^= (work << 16); + work = ((right >> 2) ^ leftt) & 0x33333333L; + leftt ^= work; + right ^= (work << 2); + work = ((right >> 8) ^ leftt) & 0x00ff00ffL; + leftt ^= work; + right ^= (work << 8); + right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL; + work = (leftt ^ right) & 0xaaaaaaaaL; + leftt ^= work; + right ^= work; + leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL; + + for( round = 0; round < 8; round++ ) { + work = (right << 28) | (right >> 4); + work ^= *keys++; + fval = SP7[ work & 0x3fL]; + fval |= SP5[(work >> 8) & 0x3fL]; + fval |= SP3[(work >> 16) & 0x3fL]; + fval |= SP1[(work >> 24) & 0x3fL]; + work = right ^ *keys++; + fval |= SP8[ work & 0x3fL]; + fval |= SP6[(work >> 8) & 0x3fL]; + fval |= SP4[(work >> 16) & 0x3fL]; + fval |= SP2[(work >> 24) & 0x3fL]; + leftt ^= fval; + work = (leftt << 28) | (leftt >> 4); + work ^= *keys++; + fval = SP7[ work & 0x3fL]; + fval |= SP5[(work >> 8) & 0x3fL]; + fval |= SP3[(work >> 16) & 0x3fL]; + fval |= SP1[(work >> 24) & 0x3fL]; + work = leftt ^ *keys++; + fval |= SP8[ work & 0x3fL]; + fval |= SP6[(work >> 8) & 0x3fL]; + fval |= SP4[(work >> 16) & 0x3fL]; + fval |= SP2[(work >> 24) & 0x3fL]; + right ^= fval; + } + + right = (right << 31) | (right >> 1); + work = (leftt ^ right) & 0xaaaaaaaaL; + leftt ^= work; + right ^= work; + leftt = (leftt << 31) | (leftt >> 1); + work = ((leftt >> 8) ^ right) & 0x00ff00ffL; + right ^= work; + leftt ^= (work << 8); + work = ((leftt >> 2) ^ right) & 0x33333333L; + right ^= work; + leftt ^= (work << 2); + work = ((right >> 16) ^ leftt) & 0x0000ffffL; + leftt ^= work; + right ^= (work << 16); + work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL; + leftt ^= work; + right ^= (work << 4); + *block++ = right; + *block = leftt; + return; + } + +/* Validation sets: + * + * Single-length key, single-length plaintext - + * Key : 0123 4567 89ab cdef + * Plain : 0123 4567 89ab cde7 + * Cipher : c957 4425 6a5e d31d + * + * Double-length key, single-length plaintext - + * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 + * Plain : 0123 4567 89ab cde7 + * Cipher : 7f1d 0a77 826b 8aff + * + * Double-length key, double-length plaintext - + * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 + * Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff + * Cipher : 27a0 8440 406a df60 278f 47cf 42d6 15d7 + * + * Triple-length key, single-length plaintext - + * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567 + * Plain : 0123 4567 89ab cde7 + * Cipher : de0b 7c06 ae5e 0ed5 + * + * Triple-length key, double-length plaintext - + * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567 + * Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff + * Cipher : ad0d 1b30 ac17 cf07 0ed1 1c63 81e4 4de5 + * + * d3des V5.0a rwo 9208.07 18:44 Graven Imagery + **********************************************************************/ diff -rupN xen-unstable.hg-16125.orig/tools/ioemu/d3des.h xen-unstable.hg-16125.new/tools/ioemu/d3des.h --- xen-unstable.hg-16125.orig/tools/ioemu/d3des.h 1969-12-31 19:00:00.000000000 -0500 +++ xen-unstable.hg-16125.new/tools/ioemu/d3des.h 2007-10-29 16:45:01.000000000 -0400 @@ -0,0 +1,51 @@ +/* + * This is D3DES (V5.09) by Richard Outerbridge with the double and + * triple-length support removed for use in VNC. + * + * These changes are: + * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* d3des.h - + * + * Headers and defines for d3des.c + * Graven Imagery, 1992. + * + * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge + * (GEnie : OUTER; CIS : [71755,204]) + */ + +#define EN0 0 /* MODE == encrypt */ +#define DE1 1 /* MODE == decrypt */ + +extern void deskey(unsigned char *, int); +/* hexkey[8] MODE + * Sets the internal key register according to the hexadecimal + * key contained in the 8 bytes of hexkey, according to the DES, + * for encryption or decryption according to MODE. + */ + +extern void usekey(unsigned long *); +/* cookedkey[32] + * Loads the internal key register with the data in cookedkey. + */ + +extern void cpkey(unsigned long *); +/* cookedkey[32] + * Copies the contents of the internal key register into the storage + * located at &cookedkey[0]. + */ + +extern void des(unsigned char *, unsigned char *); +/* from[8] to[8] + * Encrypts/Decrypts (according to the key currently loaded in the + * internal key register) one block of eight bytes at address ''from'' + * into the block at address ''to''. They can be the same. + */ + +/* d3des.h V5.09 rwo 9208.04 15:06 Graven Imagery + ********************************************************************/ diff -rupN xen-unstable.hg-16125.orig/tools/ioemu/Makefile.target xen-unstable.hg-16125.new/tools/ioemu/Makefile.target --- xen-unstable.hg-16125.orig/tools/ioemu/Makefile.target 2007-10-29 16:44:22.000000000 -0400 +++ xen-unstable.hg-16125.new/tools/ioemu/Makefile.target 2007-10-29 16:45:01.000000000 -0400 @@ -387,6 +387,11 @@ SOUND_HW += fmopl.o adlib.o endif AUDIODRV+= wavcapture.o +ifdef CONFIG_VNC_TLS +CPPFLAGS += $(CONFIG_VNC_TLS_CFLAGS) +LIBS += $(CONFIG_VNC_TLS_LIBS) +endif + # SCSI layer VL_OBJS+= scsi-disk.o cdrom.o lsi53c895a.o @@ -456,7 +461,7 @@ endif ifdef CONFIG_SDL VL_OBJS+=sdl.o x_keymap.o endif -VL_OBJS+=vnc.o +VL_OBJS+=vnc.o d3des.o ifdef CONFIG_COCOA VL_OBJS+=cocoa.o COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa -framework IOKit @@ -514,7 +519,7 @@ cocoa.o: cocoa.m sdl.o: sdl.c keymaps.c sdl_keysym.h $(CC) $(CFLAGS) $(CPPFLAGS) $(SDL_CFLAGS) $(BASE_CFLAGS) -c -o $@ $< -vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h +vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h d3des.c d3des.h $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< sdlaudio.o: sdlaudio.c diff -rupN xen-unstable.hg-16125.orig/tools/ioemu/monitor.c xen-unstable.hg-16125.new/tools/ioemu/monitor.c --- xen-unstable.hg-16125.orig/tools/ioemu/monitor.c 2007-10-19 09:51:31.000000000 -0400 +++ xen-unstable.hg-16125.new/tools/ioemu/monitor.c 2007-10-29 16:45:01.000000000 -0400 @@ -374,7 +374,7 @@ void do_eject(int force, const char *fil eject_device(bs, force); } -void do_change(const char *device, const char *filename) +static void do_change_block(const char *device, const char *filename) { BlockDriverState *bs; int i; @@ -399,6 +399,30 @@ void do_change(const char *device, const } } +static void do_change_vnc(const char *target) +{ + if (strcmp(target, "passwd") == 0 || + strcmp(target, "password") == 0) { + char password[9]; + monitor_readline("Password: ", 1, password, sizeof(password)-1); + password[sizeof(password)-1] = ''\0''; + if (vnc_display_password(NULL, password) < 0) + term_printf("could not set VNC server password\n"); + } else { + if (vnc_display_open(NULL, target, 0) < 0) + term_printf("could not start VNC server on %s\n", target); + } +} + +void do_change(const char *device, const char *target) +{ + if (strcmp(device, "vnc") == 0) { + do_change_vnc(target); + } else { + do_change_block(device, target); + } +} + static void do_screen_dump(const char *filename) { vga_hw_screen_dump(filename); diff -rupN xen-unstable.hg-16125.orig/tools/ioemu/vl.c xen-unstable.hg-16125.new/tools/ioemu/vl.c --- xen-unstable.hg-16125.orig/tools/ioemu/vl.c 2007-10-29 16:44:22.000000000 -0400 +++ xen-unstable.hg-16125.new/tools/ioemu/vl.c 2007-10-29 16:58:03.000000000 -0400 @@ -7683,8 +7683,14 @@ int main(int argc, char **argv) dumb_display_init(ds); } else if (vnc_display != NULL || vncunused != 0) { int vnc_display_port; - vnc_display_port = vnc_display_init(ds, vnc_display, vncunused); - if (vncviewer) + char password[20]; + vnc_display_init(ds); + if (xenstore_read_vncpasswd(domid, password, sizeof(password)) < 0) + exit(0); + vnc_display_password(ds, password); + if ((vnc_display_port = vnc_display_open(ds, vnc_display, vncunused)) < 0) + exit (0); + if (vncviewer) vnc_start_viewer(vnc_display_port); xenstore_write_vncport(vnc_display_port); } else { diff -rupN xen-unstable.hg-16125.orig/tools/ioemu/vl.h xen-unstable.hg-16125.new/tools/ioemu/vl.h --- xen-unstable.hg-16125.orig/tools/ioemu/vl.h 2007-10-29 16:44:22.000000000 -0400 +++ xen-unstable.hg-16125.new/tools/ioemu/vl.h 2007-10-29 16:45:01.000000000 -0400 @@ -943,7 +943,10 @@ void sdl_display_init(DisplayState *ds, void cocoa_display_init(DisplayState *ds, int full_screen); /* vnc.c */ -int vnc_display_init(DisplayState *ds, const char *display, int find_unused); +void vnc_display_init(DisplayState *ds); +void vnc_display_close(DisplayState *ds); +int vnc_display_open(DisplayState *ds, const char * display, int find_unused); +int vnc_display_password(DisplayState *ds, const char *password); void do_info_vnc(void); int vnc_start_viewer(int port); diff -rupN xen-unstable.hg-16125.orig/tools/ioemu/vnc-37 xen-unstable.hg-16125.new/tools/ioemu/vnc-37 --- xen-unstable.hg-16125.orig/tools/ioemu/vnc-37 1969-12-31 19:00:00.000000000 -0500 +++ xen-unstable.hg-16125.new/tools/ioemu/vnc-37 2007-10-29 17:21:17.000000000 -0400 @@ -0,0 +1,20 @@ +According to http://www.realvnc.com/docs/rfbproto.pdf section 6.2.1, +when handling older clients, SecurityResult should not be sent. + +diff --git a/vnc.c b/vnc.c +index 72c8d1c..8ae671a 100644 +--- a/vnc.c ++++ b/vnc.c +@@ -1775,7 +1775,10 @@ static int protocol_client_auth(VncState *vs, char *data, size_t len) + switch (vs->auth) { + case VNC_AUTH_NONE: + VNC_DEBUG("Accept auth none\n"); +- vnc_write_u32(vs, 0); /* Accept auth completion */ ++ if (vs->minor >= 8) { ++ vnc_write_u32(vs, 0); /* Accept auth completion */ ++ vnc_flush(vs); ++ } + vnc_read_when(vs, protocol_client_init, 1); + break; + + diff -rupN xen-unstable.hg-16125.orig/tools/ioemu/vnc.c xen-unstable.hg-16125.new/tools/ioemu/vnc.c --- xen-unstable.hg-16125.orig/tools/ioemu/vnc.c 2007-10-29 16:44:22.000000000 -0400 +++ xen-unstable.hg-16125.new/tools/ioemu/vnc.c 2007-10-29 17:21:23.000000000 -0400 @@ -47,6 +47,28 @@ #include "vnc_keysym.h" #include "keymaps.c" +#include "d3des.h" + +#if CONFIG_VNC_TLS +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#endif /* CONFIG_VNC_TLS */ + +// #define _VNC_DEBUG 1 + +#if _VNC_DEBUG +#define VNC_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) + +#if CONFIG_VNC_TLS && _VNC_DEBUG >= 2 +/* Very verbose, so only enabled for _VNC_DEBUG >= 2 */ +static void vnc_debug_gnutls_log(int level, const char* str) { + VNC_DEBUG("%d %s", level, str); +} +#endif /* CONFIG_VNC_TLS && _VNC_DEBUG */ +#else +#define VNC_DEBUG(fmt, ...) do { } while (0) +#endif + typedef struct Buffer { @@ -73,6 +95,45 @@ typedef void VncSendHextileTile(VncState #define VNC_DIRTY_WORDS (VNC_MAX_WIDTH / (16 * 32)) #endif +#define VNC_AUTH_CHALLENGE_SIZE 16 + +enum { + VNC_AUTH_INVALID = 0, + VNC_AUTH_NONE = 1, + VNC_AUTH_VNC = 2, + VNC_AUTH_RA2 = 5, + VNC_AUTH_RA2NE = 6, + VNC_AUTH_TIGHT = 16, + VNC_AUTH_ULTRA = 17, + VNC_AUTH_TLS = 18, + VNC_AUTH_VENCRYPT = 19 +}; + +#if CONFIG_VNC_TLS +enum { + VNC_WIREMODE_CLEAR, + VNC_WIREMODE_TLS, +}; + +enum { + VNC_AUTH_VENCRYPT_PLAIN = 256, + VNC_AUTH_VENCRYPT_TLSNONE = 257, + VNC_AUTH_VENCRYPT_TLSVNC = 258, + VNC_AUTH_VENCRYPT_TLSPLAIN = 259, + VNC_AUTH_VENCRYPT_X509NONE = 260, + VNC_AUTH_VENCRYPT_X509VNC = 261, + VNC_AUTH_VENCRYPT_X509PLAIN = 262, +}; + +#if CONFIG_VNC_TLS +#define X509_CA_CERT_FILE "ca-cert.pem" +#define X509_CA_CRL_FILE "ca-crl.pem" +#define X509_SERVER_KEY_FILE "server-key.pem" +#define X509_SERVER_CERT_FILE "server-cert.pem" +#endif + +#endif /* CONFIG_VNC_TLS */ + struct VncState { QEMUTimer *timer; @@ -97,7 +158,27 @@ struct VncState int last_x; int last_y; - const char *display; + int major; + int minor; + + char *display; + char *password; + int auth; +#if CONFIG_VNC_TLS + int subauth; + int x509verify; + + char *x509cacert; + char *x509cacrl; + char *x509cert; + char *x509key; +#endif + char challenge[VNC_AUTH_CHALLENGE_SIZE]; + +#if CONFIG_VNC_TLS + int wiremode; + gnutls_session_t tls_session; +#endif Buffer output; Buffer input; @@ -698,11 +779,19 @@ static int vnc_client_io_error(VncState if (ret == -1 && (last_errno == EINTR || last_errno == EAGAIN)) return 0; + VNC_DEBUG("Closing down client sock %d %d\n", ret, ret < 0 ? last_errno : 0); qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL); closesocket(vs->csock); vs->csock = -1; buffer_reset(&vs->input); buffer_reset(&vs->output); +#if CONFIG_VNC_TLS + if (vs->tls_session) { + gnutls_deinit(vs->tls_session); + vs->tls_session = NULL; + } + vs->wiremode = VNC_WIREMODE_CLEAR; +#endif /* CONFIG_VNC_TLS */ return 0; } return ret; @@ -718,7 +807,19 @@ static void vnc_client_write(void *opaqu long ret; VncState *vs = opaque; - ret = send(vs->csock, vs->output.buffer, vs->output.offset, 0); +#if CONFIG_VNC_TLS + if (vs->tls_session) { + ret = gnutls_write(vs->tls_session, vs->output.buffer, vs->output.offset); + if (ret < 0) { + if (ret == GNUTLS_E_AGAIN) + errno = EAGAIN; + else + errno = EIO; + ret = -1; + } + } else +#endif /* CONFIG_VNC_TLS */ + ret = send(vs->csock, vs->output.buffer, vs->output.offset, 0); ret = vnc_client_io_error(vs, ret, socket_error()); if (!ret) return; @@ -744,7 +845,19 @@ static void vnc_client_read(void *opaque buffer_reserve(&vs->input, 4096); - ret = recv(vs->csock, buffer_end(&vs->input), 4096, 0); +#if CONFIG_VNC_TLS + if (vs->tls_session) { + ret = gnutls_read(vs->tls_session, buffer_end(&vs->input), 4096); + if (ret < 0) { + if (ret == GNUTLS_E_AGAIN) + errno = EAGAIN; + else + errno = EIO; + ret = -1; + } + } else +#endif /* CONFIG_VNC_TLS */ + ret = recv(vs->csock, buffer_end(&vs->input), 4096, 0); ret = vnc_client_io_error(vs, ret, socket_error()); if (!ret) return; @@ -841,6 +954,41 @@ static uint32_t read_u32(uint8_t *data, (data[offset + 2] << 8) | data[offset + 3]); } +#if CONFIG_VNC_TLS +ssize_t vnc_tls_push(gnutls_transport_ptr_t transport, + const void *data, + size_t len) { + struct VncState *vs = (struct VncState *)transport; + int ret; + + retry: + ret = send(vs->csock, data, len, 0); + if (ret < 0) { + if (errno == EINTR) + goto retry; + return -1; + } + return ret; +} + + +ssize_t vnc_tls_pull(gnutls_transport_ptr_t transport, + void *data, + size_t len) { + struct VncState *vs = (struct VncState *)transport; + int ret; + + retry: + ret = recv(vs->csock, data, len, 0); + if (ret < 0) { + if (errno == EINTR) + goto retry; + return -1; + } + return ret; +} +#endif /* CONFIG_VNC_TLS */ + static void client_cut_text(VncState *vs, size_t len, char *text) { } @@ -1384,23 +1532,591 @@ static int protocol_client_init(VncState } -static int protocol_version(VncState *vs, uint8_t *version, size_t len) +static void make_challenge(VncState *vs) +{ + int i; + + srand(time(NULL)+getpid()+getpid()*987654+rand()); + + for (i = 0 ; i < sizeof(vs->challenge) ; i++) + vs->challenge[i] = (int) (256.0*rand()/(RAND_MAX+1.0)); +} + +static int protocol_client_auth_vnc(VncState *vs, char *data, size_t len) +{ + char response[VNC_AUTH_CHALLENGE_SIZE]; + int i, j, pwlen; + char key[8]; + + if (!vs->password || !vs->password[0]) { + VNC_DEBUG("No password configured on server"); + vnc_write_u32(vs, 1); /* Reject auth */ + if (vs->minor >= 8) { + static const char err[] = "Authentication failed"; + vnc_write_u32(vs, sizeof(err)); + vnc_write(vs, err, sizeof(err)); + } + vnc_flush(vs); + vnc_client_error(vs); + return 0; + } + + memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE); + + /* Calculate the expected challenge response */ + pwlen = strlen(vs->password); + for (i=0; i<sizeof(key); i++) + key[i] = i<pwlen ? vs->password[i] : 0; + deskey(key, EN0); + for (j = 0; j < VNC_AUTH_CHALLENGE_SIZE; j += 8) + des(response+j, response+j); + + /* Compare expected vs actual challenge response */ + if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) { + VNC_DEBUG("Client challenge reponse did not match\n"); + vnc_write_u32(vs, 1); /* Reject auth */ + if (vs->minor >= 8) { + static const char err[] = "Authentication failed"; + vnc_write_u32(vs, sizeof(err)); + vnc_write(vs, err, sizeof(err)); + } + vnc_flush(vs); + vnc_client_error(vs); + } else { + VNC_DEBUG("Accepting VNC challenge response\n"); + vnc_write_u32(vs, 0); /* Accept auth */ + vnc_flush(vs); + + vnc_read_when(vs, protocol_client_init, 1); + } + return 0; +} + +static int start_auth_vnc(VncState *vs) +{ + make_challenge(vs); + /* Send client a ''random'' challenge */ + vnc_write(vs, vs->challenge, sizeof(vs->challenge)); + vnc_flush(vs); + + vnc_read_when(vs, protocol_client_auth_vnc, sizeof(vs->challenge)); + return 0; +} + + +#if CONFIG_VNC_TLS +#define DH_BITS 1024 +static gnutls_dh_params_t dh_params; + +static int vnc_tls_initialize(void) +{ + static int tlsinitialized = 0; + + if (tlsinitialized) + return 1; + + if (gnutls_global_init () < 0) + return 0; + + /* XXX ought to re-generate diffie-hellmen params periodically */ + if (gnutls_dh_params_init (&dh_params) < 0) + return 0; + if (gnutls_dh_params_generate2 (dh_params, DH_BITS) < 0) + return 0; + +#if _VNC_DEBUG == 2 + gnutls_global_set_log_level(10); + gnutls_global_set_log_function(vnc_debug_gnutls_log); +#endif + + tlsinitialized = 1; + + return 1; +} + +static gnutls_anon_server_credentials vnc_tls_initialize_anon_cred(void) +{ + gnutls_anon_server_credentials anon_cred; + int ret; + + if ((ret = gnutls_anon_allocate_server_credentials(&anon_cred)) < 0) { + VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret)); + return NULL; + } + + gnutls_anon_set_server_dh_params(anon_cred, dh_params); + + return anon_cred; +} + + +static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(VncState *vs) +{ + gnutls_certificate_credentials_t x509_cred; + int ret; + + if (!vs->x509cacert) { + VNC_DEBUG("No CA x509 certificate specified\n"); + return NULL; + } + if (!vs->x509cert) { + VNC_DEBUG("No server x509 certificate specified\n"); + return NULL; + } + if (!vs->x509key) { + VNC_DEBUG("No server private key specified\n"); + return NULL; + } + + if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) { + VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret)); + return NULL; + } + if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred, + vs->x509cacert, + GNUTLS_X509_FMT_PEM)) < 0) { + VNC_DEBUG("Cannot load CA certificate %s\n", gnutls_strerror(ret)); + gnutls_certificate_free_credentials(x509_cred); + return NULL; + } + + if ((ret = gnutls_certificate_set_x509_key_file (x509_cred, + vs->x509cert, + vs->x509key, + GNUTLS_X509_FMT_PEM)) < 0) { + VNC_DEBUG("Cannot load certificate & key %s\n", gnutls_strerror(ret)); + gnutls_certificate_free_credentials(x509_cred); + return NULL; + } + + if (vs->x509cacrl) { + if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred, + vs->x509cacrl, + GNUTLS_X509_FMT_PEM)) < 0) { + VNC_DEBUG("Cannot load CRL %s\n", gnutls_strerror(ret)); + gnutls_certificate_free_credentials(x509_cred); + return NULL; + } + } + + gnutls_certificate_set_dh_params (x509_cred, dh_params); + + return x509_cred; +} + +static int vnc_validate_certificate(struct VncState *vs) +{ + int ret; + unsigned int status; + const gnutls_datum_t *certs; + unsigned int nCerts, i; + time_t now; + + VNC_DEBUG("Validating client certificate\n"); + if ((ret = gnutls_certificate_verify_peers2 (vs->tls_session, &status)) < 0) { + VNC_DEBUG("Verify failed %s\n", gnutls_strerror(ret)); + return -1; + } + + if ((now = time(NULL)) == ((time_t)-1)) { + return -1; + } + + if (status != 0) { + if (status & GNUTLS_CERT_INVALID) + VNC_DEBUG("The certificate is not trusted.\n"); + + if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) + VNC_DEBUG("The certificate hasn''t got a known issuer.\n"); + + if (status & GNUTLS_CERT_REVOKED) + VNC_DEBUG("The certificate has been revoked.\n"); + + if (status & GNUTLS_CERT_INSECURE_ALGORITHM) + VNC_DEBUG("The certificate uses an insecure algorithm\n"); + + return -1; + } else { + VNC_DEBUG("Certificate is valid!\n"); + } + + /* Only support x509 for now */ + if (gnutls_certificate_type_get(vs->tls_session) != GNUTLS_CRT_X509) + return -1; + + if (!(certs = gnutls_certificate_get_peers(vs->tls_session, &nCerts))) + return -1; + + for (i = 0 ; i < nCerts ; i++) { + gnutls_x509_crt_t cert; + VNC_DEBUG ("Checking certificate chain %d\n", i); + if (gnutls_x509_crt_init (&cert) < 0) + return -1; + + if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) { + gnutls_x509_crt_deinit (cert); + return -1; + } + + if (gnutls_x509_crt_get_expiration_time (cert) < now) { + VNC_DEBUG("The certificate has expired\n"); + gnutls_x509_crt_deinit (cert); + return -1; + } + + if (gnutls_x509_crt_get_activation_time (cert) > now) { + VNC_DEBUG("The certificate is not yet activated\n"); + gnutls_x509_crt_deinit (cert); + return -1; + } + + if (gnutls_x509_crt_get_activation_time (cert) > now) { + VNC_DEBUG("The certificate is not yet activated\n"); + gnutls_x509_crt_deinit (cert); + return -1; + } + + gnutls_x509_crt_deinit (cert); + } + + return 0; +} + + +static int start_auth_vencrypt_subauth(VncState *vs) +{ + switch (vs->subauth) { + case VNC_AUTH_VENCRYPT_TLSNONE: + case VNC_AUTH_VENCRYPT_X509NONE: + VNC_DEBUG("Accept TLS auth none\n"); + vnc_write_u32(vs, 0); /* Accept auth completion */ + vnc_read_when(vs, protocol_client_init, 1); + break; + + case VNC_AUTH_VENCRYPT_TLSVNC: + case VNC_AUTH_VENCRYPT_X509VNC: + VNC_DEBUG("Start TLS auth VNC\n"); + return start_auth_vnc(vs); + + default: /* Should not be possible, but just in case */ + VNC_DEBUG("Reject auth %d\n", vs->auth); + vnc_write_u8(vs, 1); + if (vs->minor >= 8) { + static const char err[] = "Unsupported authentication type"; + vnc_write_u32(vs, sizeof(err)); + vnc_write(vs, err, sizeof(err)); + } + vnc_client_error(vs); + } + + return 0; +} + +static void vnc_handshake_io(void *opaque); + +static int vnc_continue_handshake(struct VncState *vs) { + int ret; + + if ((ret = gnutls_handshake(vs->tls_session)) < 0) { + if (!gnutls_error_is_fatal(ret)) { + VNC_DEBUG("Handshake interrupted (blocking)\n"); + if (!gnutls_record_get_direction(vs->tls_session)) + qemu_set_fd_handler(vs->csock, vnc_handshake_io, NULL, vs); + else + qemu_set_fd_handler(vs->csock, NULL, vnc_handshake_io, vs); + return 0; + } + VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret)); + vnc_client_error(vs); + return -1; + } + + if (vs->x509verify) { + if (vnc_validate_certificate(vs) < 0) { + VNC_DEBUG("Client verification failed\n"); + vnc_client_error(vs); + return -1; + } else { + VNC_DEBUG("Client verification passed\n"); + } + } + + VNC_DEBUG("Handshake done, switching to TLS data mode\n"); + vs->wiremode = VNC_WIREMODE_TLS; + qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs); + + return start_auth_vencrypt_subauth(vs); +} + +static void vnc_handshake_io(void *opaque) { + struct VncState *vs = (struct VncState *)opaque; + + VNC_DEBUG("Handshake IO continue\n"); + vnc_continue_handshake(vs); +} + +#define NEED_X509_AUTH(vs) \ + ((vs)->subauth == VNC_AUTH_VENCRYPT_X509NONE || \ + (vs)->subauth == VNC_AUTH_VENCRYPT_X509VNC || \ + (vs)->subauth == VNC_AUTH_VENCRYPT_X509PLAIN) + + +static int vnc_start_tls(struct VncState *vs) { + 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}; + + VNC_DEBUG("Do TLS setup\n"); + 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, NEED_X509_AUTH(vs) ? kx_x509 : kx_anon) < 0) { + gnutls_deinit(vs->tls_session); + vs->tls_session = NULL; + 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; + 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; + vnc_client_error(vs); + return -1; + } + + if (NEED_X509_AUTH(vs)) { + gnutls_certificate_server_credentials x509_cred = vnc_tls_initialize_x509_cred(vs); + if (!x509_cred) { + gnutls_deinit(vs->tls_session); + vs->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; + gnutls_certificate_free_credentials(x509_cred); + vnc_client_error(vs); + return -1; + } + if (vs->x509verify) { + VNC_DEBUG("Requesting a client certificate\n"); + gnutls_certificate_server_set_request (vs->tls_session, GNUTLS_CERT_REQUEST); + } + + } else { + gnutls_anon_server_credentials anon_cred = vnc_tls_initialize_anon_cred(); + if (!anon_cred) { + gnutls_deinit(vs->tls_session); + vs->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; + 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); + } + + VNC_DEBUG("Start TLS handshake process\n"); + return vnc_continue_handshake(vs); +} + +static int protocol_client_vencrypt_auth(VncState *vs, char *data, size_t len) +{ + int auth = read_u32(data, 0); + + if (auth != vs->subauth) { + VNC_DEBUG("Rejecting auth %d\n", auth); + vnc_write_u8(vs, 0); /* Reject auth */ + vnc_flush(vs); + vnc_client_error(vs); + } else { + VNC_DEBUG("Accepting auth %d, starting handshake\n", auth); + vnc_write_u8(vs, 1); /* Accept auth */ + vnc_flush(vs); + + if (vnc_start_tls(vs) < 0) { + VNC_DEBUG("Failed to complete TLS\n"); + return 0; + } + + if (vs->wiremode == VNC_WIREMODE_TLS) { + VNC_DEBUG("Starting VeNCrypt subauth\n"); + return start_auth_vencrypt_subauth(vs); + } else { + VNC_DEBUG("TLS handshake blocked\n"); + return 0; + } + } + return 0; +} + +static int protocol_client_vencrypt_init(VncState *vs, char *data, size_t len) +{ + if (data[0] != 0 || + data[1] != 2) { + VNC_DEBUG("Unsupported VeNCrypt protocol %d.%d\n", (int)data[0], (int)data[1]); + vnc_write_u8(vs, 1); /* Reject version */ + vnc_flush(vs); + vnc_client_error(vs); + } else { + VNC_DEBUG("Sending allowed auth %d\n", vs->subauth); + vnc_write_u8(vs, 0); /* Accept version */ + vnc_write_u8(vs, 1); /* Number of sub-auths */ + vnc_write_u32(vs, vs->subauth); /* The supported auth */ + vnc_flush(vs); + vnc_read_when(vs, protocol_client_vencrypt_auth, 4); + } + return 0; +} + +static int start_auth_vencrypt(VncState *vs) +{ + /* Send VeNCrypt version 0.2 */ + vnc_write_u8(vs, 0); + vnc_write_u8(vs, 2); + + vnc_read_when(vs, protocol_client_vencrypt_init, 2); + return 0; +} +#endif /* CONFIG_VNC_TLS */ + +static int protocol_client_auth(VncState *vs, char *data, size_t len) +{ + /* We only advertise 1 auth scheme at a time, so client + * must pick the one we sent. Verify this */ + if (data[0] != vs->auth) { /* Reject auth */ + VNC_DEBUG("Reject auth %d\n", (int)data[0]); + vnc_write_u32(vs, 1); + if (vs->minor >= 8) { + static const char err[] = "Authentication failed"; + vnc_write_u32(vs, sizeof(err)); + vnc_write(vs, err, sizeof(err)); + } + vnc_client_error(vs); + } else { /* Accept requested auth */ + VNC_DEBUG("Client requested auth %d\n", (int)data[0]); + switch (vs->auth) { + case VNC_AUTH_NONE: + VNC_DEBUG("Accept auth none\n"); + if (vs->minor >= 8) { + vnc_write_u32(vs, 0); /* Accept auth completion */ + vnc_flush(vs); + } + vnc_read_when(vs, protocol_client_init, 1); + break; + + case VNC_AUTH_VNC: + VNC_DEBUG("Start VNC auth\n"); + return start_auth_vnc(vs); + +#if CONFIG_VNC_TLS + case VNC_AUTH_VENCRYPT: + VNC_DEBUG("Accept VeNCrypt auth\n");; + return start_auth_vencrypt(vs); +#endif /* CONFIG_VNC_TLS */ + + default: /* Should not be possible, but just in case */ + VNC_DEBUG("Reject auth %d\n", vs->auth); + vnc_write_u8(vs, 1); + if (vs->minor >= 8) { + static const char err[] = "Authentication failed"; + vnc_write_u32(vs, sizeof(err)); + vnc_write(vs, err, sizeof(err)); + } + vnc_client_error(vs); + } + } + return 0; +} + +static int protocol_version(VncState *vs, char *version, size_t len) { char local[13]; - int maj, min; memcpy(local, version, 12); local[12] = 0; - if (sscanf(local, "RFB %03d.%03d\n", &maj, &min) != 2) { + if (sscanf(local, "RFB %03d.%03d\n", &vs->major, &vs->minor) != 2) { + VNC_DEBUG("Malformed protocol version %s\n", local); vnc_client_error(vs); return 0; } - - vnc_write_u32(vs, 1); /* None */ - vnc_flush(vs); - - vnc_read_when(vs, protocol_client_init, 1); + VNC_DEBUG("Client request protocol version %d.%d\n", vs->major, vs->minor); + if (vs->major != 3 || + (vs->minor != 3 && + vs->minor != 4 && + vs->minor != 5 && + vs->minor != 7 && + vs->minor != 8)) { + VNC_DEBUG("Unsupported client version\n"); + vnc_write_u32(vs, VNC_AUTH_INVALID); + vnc_flush(vs); + vnc_client_error(vs); + return 0; + } + /* Some broken clients report v3.4 or v3.5, which spec requires to be treated + * as equivalent to v3.3 by servers + */ + if (vs->minor == 4 || vs->minor == 5) + vs->minor = 3; + + if (vs->minor == 3) { + if (vs->auth == VNC_AUTH_NONE) { + VNC_DEBUG("Tell client auth none\n"); + vnc_write_u32(vs, vs->auth); + vnc_flush(vs); + vnc_read_when(vs, protocol_client_init, 1); + } else if (vs->auth == VNC_AUTH_VNC) { + VNC_DEBUG("Tell client VNC auth\n"); + vnc_write_u32(vs, vs->auth); + vnc_flush(vs); + start_auth_vnc(vs); + } else { + VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->auth); + vnc_write_u32(vs, VNC_AUTH_INVALID); + vnc_flush(vs); + vnc_client_error(vs); + } + } else { + VNC_DEBUG("Telling client we support auth %d\n", vs->auth); + vnc_write_u8(vs, 1); /* num auth */ + vnc_write_u8(vs, vs->auth); + vnc_read_when(vs, protocol_client_auth, 1); + vnc_flush(vs); + } return 0; } @@ -1413,9 +2129,10 @@ static void vnc_listen_read(void *opaque vs->csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen); if (vs->csock != -1) { + VNC_DEBUG("New client on socket %d\n", vs->csock); socket_set_nonblock(vs->csock); qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, opaque); - vnc_write(vs, "RFB 003.003\n", 12); + vnc_write(vs, "RFB 003.008\n", 12); vnc_flush(vs); vnc_read_when(vs, protocol_version, 12); framebuffer_set_updated(vs, 0, 0, vs->ds->width, vs->ds->height); @@ -1428,16 +2145,8 @@ static void vnc_listen_read(void *opaque extern int parse_host_port(struct sockaddr_in *saddr, const char *str); -int vnc_display_init(DisplayState *ds, const char *arg, int find_unused) +void vnc_display_init(DisplayState *ds) { - struct sockaddr *addr; - struct sockaddr_in iaddr; -#ifndef _WIN32 - struct sockaddr_un uaddr; -#endif - int reuse_addr, ret; - socklen_t addrlen; - const char *p; VncState *vs; vs = qemu_mallocz(sizeof(VncState)); @@ -1446,7 +2155,8 @@ int vnc_display_init(DisplayState *ds, c ds->opaque = vs; vnc_state = vs; - vs->display = arg; + vs->display = NULL; + vs->password = NULL; vs->lsock = -1; vs->csock = -1; @@ -1470,19 +2180,238 @@ int vnc_display_init(DisplayState *ds, c vs->ds->dpy_refresh = vnc_dpy_refresh; vnc_dpy_resize(vs->ds, 640, 400); +} - if (arg == NULL) - arg = "localhost:0"; - +#if CONFIG_VNC_TLS +static int vnc_set_x509_credential(VncState *vs, + const char *certdir, + const char *filename, + char **cred, + int ignoreMissing) +{ + struct stat sb; + + if (*cred) { + qemu_free(*cred); + *cred = NULL; + } + + if (!(*cred = qemu_malloc(strlen(certdir) + strlen(filename) + 2))) + return -1; + + strcpy(*cred, certdir); + strcat(*cred, "/"); + strcat(*cred, filename); + + VNC_DEBUG("Check %s\n", *cred); + if (stat(*cred, &sb) < 0) { + qemu_free(*cred); + *cred = NULL; + if (ignoreMissing && errno == ENOENT) + return 0; + return -1; + } + + return 0; +} + +static int vnc_set_x509_credential_dir(VncState *vs, + const char *certdir) +{ + if (vnc_set_x509_credential(vs, certdir, X509_CA_CERT_FILE, &vs->x509cacert, 0) < 0) + goto cleanup; + if (vnc_set_x509_credential(vs, certdir, X509_CA_CRL_FILE, &vs->x509cacrl, 1) < 0) + goto cleanup; + if (vnc_set_x509_credential(vs, certdir, X509_SERVER_CERT_FILE, &vs->x509cert, 0) < 0) + goto cleanup; + if (vnc_set_x509_credential(vs, certdir, X509_SERVER_KEY_FILE, &vs->x509key, 0) < 0) + goto cleanup; + + return 0; + + cleanup: + qemu_free(vs->x509cacert); + qemu_free(vs->x509cacrl); + qemu_free(vs->x509cert); + qemu_free(vs->x509key); + vs->x509cacert = vs->x509cacrl = vs->x509cert = vs->x509key = NULL; + return -1; +} +#endif /* CONFIG_VNC_TLS */ + +void vnc_display_close(DisplayState *ds) +{ + VncState *vs = ds ? (VncState *)ds->opaque : vnc_state; + + if (vs->display) { + qemu_free(vs->display); + vs->display = NULL; + } + if (vs->lsock != -1) { + qemu_set_fd_handler2(vs->lsock, NULL, NULL, NULL, NULL); + close(vs->lsock); + vs->lsock = -1; + } + if (vs->csock != -1) { + qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL); + closesocket(vs->csock); + vs->csock = -1; + buffer_reset(&vs->input); + buffer_reset(&vs->output); +#if CONFIG_VNC_TLS + if (vs->tls_session) { + gnutls_deinit(vs->tls_session); + vs->tls_session = NULL; + } + vs->wiremode = VNC_WIREMODE_CLEAR; +#endif /* CONFIG_VNC_TLS */ + } + vs->auth = VNC_AUTH_INVALID; +#if CONFIG_VNC_TLS + vs->subauth = VNC_AUTH_INVALID; + vs->x509verify = 0; +#endif +} + +int parse_host_port(struct sockaddr_in *saddr, const char *str); + + + +int vnc_display_password(DisplayState *ds, const char *password) +{ + VncState *vs = ds ? (VncState *)ds->opaque : vnc_state; + + if (vs->password) { + qemu_free(vs->password); + vs->password = NULL; + } + if (password && password[0]) { + if (!(vs->password = qemu_strdup(password))) + return -1; + } + + return 0; +} + +int vnc_display_open(DisplayState *ds, const char *display, int find_unused) +{ + struct sockaddr *addr; + struct sockaddr_in iaddr; #ifndef _WIN32 - if (strstart(arg, "unix:", &p)) { + struct sockaddr_un uaddr; +#endif + int reuse_addr, ret; + socklen_t addrlen; + const char *p; + VncState *vs = ds ? (VncState *)ds->opaque : vnc_state; + const char *options; + int password = 0; +#if CONFIG_VNC_TLS + int tls = 0, x509 = 0; +#endif + + if (display == NULL) + display = "localhost:0"; + + vnc_display_close(ds); + if (strcmp(display, "none") == 0) + return 0; + + if (!(vs->display = strdup(display))) + return -1; + + options = display; + while ((options = strchr(options, '',''))) { + options++; + if (strncmp(options, "password", 8) == 0) { + password = 1; /* Require password auth */ +#if CONFIG_VNC_TLS + } else if (strncmp(options, "tls", 3) == 0) { + tls = 1; /* Require TLS */ + } else if (strncmp(options, "x509", 4) == 0) { + char *start, *end; + x509 = 1; /* Require x509 certificates */ + if (strncmp(options, "x509verify", 10) == 0) + vs->x509verify = 1; /* ...and verify client certs */ + + /* Now check for ''x509=/some/path'' postfix + * and use that to setup x509 certificate/key paths */ + start = strchr(options, ''=''); + end = strchr(options, '',''); + if (start && (!end || (start < end))) { + int len = end ? end-(start+1) : strlen(start+1); + char *path = qemu_malloc(len+1); + strncpy(path, start+1, len); + path[len] = ''\0''; + VNC_DEBUG("Trying certificate path ''%s''\n", path); + if (vnc_set_x509_credential_dir(vs, path) < 0) { + fprintf(stderr, "Failed to find x509 certificates/keys in %s\n", path); + qemu_free(path); + qemu_free(vs->display); + vs->display = NULL; + return -1; + } + qemu_free(path); + } else { + fprintf(stderr, "No certificate path provided\n"); + qemu_free(vs->display); + vs->display = NULL; + return -1; + } +#endif + } + } + + if (password) { +#if CONFIG_VNC_TLS + if (tls) { + vs->auth = VNC_AUTH_VENCRYPT; + if (x509) { + VNC_DEBUG("Initializing VNC server with x509 password auth\n"); + vs->subauth = VNC_AUTH_VENCRYPT_X509VNC; + } else { + VNC_DEBUG("Initializing VNC server with TLS password auth\n"); + vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC; + } + } else { +#endif + VNC_DEBUG("Initializing VNC server with password auth\n"); + vs->auth = VNC_AUTH_VNC; +#if CONFIG_VNC_TLS + vs->subauth = VNC_AUTH_INVALID; + } +#endif + } else { +#if CONFIG_VNC_TLS + if (tls) { + vs->auth = VNC_AUTH_VENCRYPT; + if (x509) { + VNC_DEBUG("Initializing VNC server with x509 no auth\n"); + vs->subauth = VNC_AUTH_VENCRYPT_X509NONE; + } else { + VNC_DEBUG("Initializing VNC server with TLS no auth\n"); + vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE; + } + } else { +#endif + VNC_DEBUG("Initializing VNC server with no auth\n"); + vs->auth = VNC_AUTH_NONE; +#if CONFIG_VNC_TLS + vs->subauth = VNC_AUTH_INVALID; + } +#endif + } +#ifndef _WIN32 + if (strstart(display, "unix:", &p)) { addr = (struct sockaddr *)&uaddr; addrlen = sizeof(uaddr); vs->lsock = socket(PF_UNIX, SOCK_STREAM, 0); if (vs->lsock == -1) { fprintf(stderr, "Could not create socket\n"); - exit(1); + free(vs->display); + vs->display = NULL; + return -1; } uaddr.sun_family = AF_UNIX; @@ -1496,25 +2425,33 @@ int vnc_display_init(DisplayState *ds, c addr = (struct sockaddr *)&iaddr; addrlen = sizeof(iaddr); + if (parse_host_port(&iaddr, display) < 0) { + fprintf(stderr, "Could not parse VNC address\n"); + free(vs->display); + vs->display = NULL; + return -1; + } + + iaddr.sin_port = htons(ntohs(iaddr.sin_port) + 5900); + vs->lsock = socket(PF_INET, SOCK_STREAM, 0); if (vs->lsock == -1) { fprintf(stderr, "Could not create socket\n"); - exit(1); + free(vs->display); + vs->display = NULL; + return -1; } - if (parse_host_port(&iaddr, arg) < 0) { - fprintf(stderr, "Could not parse VNC address\n"); - exit(1); - } - - iaddr.sin_port = htons(ntohs(iaddr.sin_port) + 5900); - reuse_addr = 1; ret = setsockopt(vs->lsock, SOL_SOCKET, SO_REUSEADDR, (const char *)&reuse_addr, sizeof(reuse_addr)); if (ret == -1) { fprintf(stderr, "setsockopt() failed\n"); - exit(1); + close(vs->lsock); + vs->lsock = -1; + free(vs->display); + vs->display = NULL; + return -1; } } @@ -1524,18 +2461,24 @@ int vnc_display_init(DisplayState *ds, c continue; } fprintf(stderr, "bind() failed\n"); - exit(1); + close(vs->lsock); + vs->lsock = -1; + free(vs->display); + vs->display = NULL; + return -1; } if (listen(vs->lsock, 1) == -1) { fprintf(stderr, "listen() failed\n"); - exit(1); + close(vs->lsock); + vs->lsock = -1; + free(vs->display); + vs->display = NULL; + return -1; } - ret = qemu_set_fd_handler2(vs->lsock, vnc_listen_poll, vnc_listen_read, NULL, vs); - if (ret == -1) { - exit(1); - } + if (qemu_set_fd_handler2(vs->lsock, vnc_listen_poll, vnc_listen_read, NULL, vs) < 0) + return -1; return ntohs(iaddr.sin_port); } diff -rupN xen-unstable.hg-16125.orig/tools/ioemu/xenstore.c xen-unstable.hg-16125.new/tools/ioemu/xenstore.c --- xen-unstable.hg-16125.orig/tools/ioemu/xenstore.c 2007-10-29 16:44:22.000000000 -0400 +++ xen-unstable.hg-16125.new/tools/ioemu/xenstore.c 2007-10-29 16:45:01.000000000 -0400 @@ -505,6 +505,7 @@ int xenstore_read_vncpasswd(int domid, c passwd = xs_read(xsh, XBT_NULL, buf, &len); if (passwd == NULL) { fprintf(logfile, "xs_read(): vncpasswd get error. %s.\n", buf); + pwbuf[0] = ''\0''; free(uuid); free(path); return rc; diff -rupN xen-unstable.hg-16125.orig/tools/python/xen/xend/image.py xen-unstable.hg-16125.new/tools/python/xen/xend/image.py --- xen-unstable.hg-16125.orig/tools/python/xen/xend/image.py 2007-10-29 16:44:22.000000000 -0400 +++ xen-unstable.hg-16125.new/tools/python/xen/xend/image.py 2007-10-29 16:45:01.000000000 -0400 @@ -31,6 +31,7 @@ from xen.xend.XendOptions import instanc from xen.xend.xenstore.xstransact import xstransact from xen.xend.xenstore.xswatch import xswatch from xen.xend import arch +from xen.xend import XendOptions xc = xen.lowlevel.xc.xc() @@ -214,27 +215,26 @@ class ImageHandler: ''vncpasswd''): if key in vmConfig[''platform'']: vnc_config[key] = vmConfig[''platform''][key] + if vnc_config.has_key("vncpasswd"): + passwd = vnc_config["vncpasswd"] + else: + passwd = XendOptions.instance().get_vncpasswd_default() + vncopts = "" + if passwd: + self.vm.storeVm("vncpasswd", passwd) + vncopts = vncopts + ",password" + log.debug("Stored a VNC password for vfb access") + else: + log.debug("No VNC passwd configured for vfb access") vnclisten = vnc_config.get(''vnclisten'', - xenopts().get_vnclisten_address()) + XendOptions.instance().get_vnclisten_address()) vncdisplay = vnc_config.get(''vncdisplay'', 0) ret.append(''-vnc'') - ret.append("%s:%d" % (vnclisten, vncdisplay)) - + ret.append("%s:%d%s" % (vnclisten, vncdisplay, vncopts)) + if vnc_config.get(''vncunused'', 0): ret.append(''-vncunused'') - - # Store vncpassword in xenstore - vncpasswd = vnc_config.get(''vncpasswd'') - if not vncpasswd: - vncpasswd = xenopts().get_vncpasswd_default() - - if vncpasswd is None: - raise VmError(''vncpasswd is not setup in vmconfig or '' - ''xend-config.sxp'') - - if vncpasswd != '''': - self.vm.storeVm(''vncpasswd'', vncpasswd) elif has_sdl: # SDL is default in QEMU. pass -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel P. Berrange
2007-Oct-29 21:53 UTC
Re: [Xen-devel] PATCH: 4/4: XenD config for VNC TLS protocol
This patch adds support to XenD for configuring the previously added TLS encryption and x509 certificate validation. At this time I have only enabled this config to be done system-wide via /etc/xen/xend-config.sxp. Since it requires the admin to add certificates on the local FS, there''s not much point in making it per VM. The x509 certificates are located in /etc/xen/vnc. Since this requires a special VNC client program (GTK-VNC, virt-viewer/virt-manager or VeNCrypt viewer) the use of TLS is disabled by default. Admins can enable it if they are using a suitable client. Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Dan. diff -rupN xen-unstable.hg-16125.orig/tools/examples/xend-config.sxp xen-unstable.hg-16125.new/tools/examples/xend-config.sxp --- xen-unstable.hg-16125.orig/tools/examples/xend-config.sxp 2007-10-29 16:44:22.000000000 -0400 +++ xen-unstable.hg-16125.new/tools/examples/xend-config.sxp 2007-10-29 17:22:39.000000000 -0400 @@ -194,6 +194,36 @@ # Empty string is no authentication. (vncpasswd '''') +# The VNC server can be told to negotiate a TLS session +# to encryption all traffic, and provide x509 cert to +# clients enalbing them to verify server identity. The +# GTK-VNC widget, virt-viewer, virt-manager and VeNCrypt +# all support the VNC extension for TLS used in QEMU. The +# TightVNC/RealVNC/UltraVNC clients do not. +# +# To enable this create x509 certificates / keys in the +# directory /etc/xen/vnc +# +# ca-cert.pem - The CA certificate +# server-cert.pem - The Server certificate signed by the CA +# server-key.pem - The server private key +# +# and then uncomment this next line +# (vnc-tls 1) + +# The certificate dir can be pointed elsewhere.. +# +# (vnc-x509-cert-dir /etc/xen/vnc) + +# The server can be told to request & validate an x509 +# certificate from the client. Only clients with a cert +# signed by the trusted CA will be able to connect. This +# is more secure the password auth alone. Passwd auth can +# used at the same time if desired. To enable client cert +# checking uncomment this: +# +# (vnc-x509-verify 1) + # The default keymap to use for the VM''s virtual keyboard # when not specififed in VM''s configuration #(keymap ''en-us'') diff -rupN xen-unstable.hg-16125.orig/tools/python/xen/xend/image.py xen-unstable.hg-16125.new/tools/python/xen/xend/image.py --- xen-unstable.hg-16125.orig/tools/python/xen/xend/image.py 2007-10-29 17:22:22.000000000 -0400 +++ xen-unstable.hg-16125.new/tools/python/xen/xend/image.py 2007-10-29 17:23:06.000000000 -0400 @@ -17,7 +17,7 @@ #=========================================================================== -import os, string +import os, os.path, string import re import math import time @@ -227,6 +227,19 @@ class ImageHandler: else: log.debug("No VNC passwd configured for vfb access") + if XendOptions.instance().get_vnc_tls(): + vncx509certdir = XendOptions.instance().get_vnc_x509_cert_dir() + vncx509verify = XendOptions.instance().get_vnc_x509_verify() + + if not os.path.exists(vncx509certdir): + raise VmError("VNC x509 certificate dir %s does not exist" % vncx509certdir) + + if vncx509verify: + vncopts = vncopts + ",tls,x509verify=%s" % vncx509certdir + else: + vncopts = vncopts + ",tls,x509=%s" % vncx509certdir + + vnclisten = vnc_config.get(''vnclisten'', XendOptions.instance().get_vnclisten_address()) vncdisplay = vnc_config.get(''vncdisplay'', 0) diff -rupN xen-unstable.hg-16125.orig/tools/python/xen/xend/XendOptions.py xen-unstable.hg-16125.new/tools/python/xen/xend/XendOptions.py --- xen-unstable.hg-16125.orig/tools/python/xen/xend/XendOptions.py 2007-10-19 09:51:32.000000000 -0400 +++ xen-unstable.hg-16125.new/tools/python/xen/xend/XendOptions.py 2007-10-29 17:22:39.000000000 -0400 @@ -102,6 +102,15 @@ class XendOptions: """Default interface to listen for VNC connections on""" xend_vnc_listen_default = ''127.0.0.1'' + """Use of TLS mode in QEMU VNC server""" + xend_vnc_tls = 0 + + """x509 certificate directory for QEMU VNC server""" + xend_vnc_x509_cert_dir = "/etc/xen/vnc" + + """Verify incoming client x509 certs""" + xend_vnc_x509_verify = 0 + """Default session storage path.""" xend_domains_path_default = ''/var/lib/xend/domains'' @@ -278,6 +287,16 @@ class XendOptions: def get_keymap(self): return self.get_config_value(''keymap'', None) + def get_vnc_tls(self): + return self.get_config_string(''vnc-tls'', self.xend_vnc_tls) + + def get_vnc_x509_cert_dir(self): + return self.get_config_string(''vnc-x509-cert-dir'', self.xend_vnc_x509_cert_dir) + + def get_vnc_x509_verify(self): + return self.get_config_string(''vnc-x509-verify'', self.xend_vnc_x509_verify) + + class XendOptionsFile(XendOptions): """Default path to the config file.""" -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Pasi Kärkkäinen
2007-Oct-30 07:53 UTC
Re: [Xen-devel] PATCH: 3/4: Add VNC auth support from upstream QEMU
On Mon, Oct 29, 2007 at 09:52:47PM +0000, Daniel P. Berrange wrote:> This patch adds in the upstream QEMU VNC authentication code. This spports the previous > VNC password auth scheme, as well as the VeNCrypt protocol extenion. The latter allows > for performing a TLS handshake, and client verification of the server identify using > x509 certificates. It is also possible for the server to request a client certificate > and validate that as a simple auth scheme. The code depends on GNU TLS for SSL APIs, > and the configure script will auto-detect this. >Hi! Might be a stupid question as I don''t know what upstream QEMU VNC supports, but would it make sense to add user+pass authentication support (via pam) ? UltraVNC supports this, at least against Windows/AD users. -- Pasi _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel P. Berrange
2007-Oct-30 13:31 UTC
Re: [Xen-devel] PATCH: 3/4: Add VNC auth support from upstream QEMU
On Tue, Oct 30, 2007 at 09:53:59AM +0200, Pasi K?rkk?inen wrote:> On Mon, Oct 29, 2007 at 09:52:47PM +0000, Daniel P. Berrange wrote: > > This patch adds in the upstream QEMU VNC authentication code. This spports the previous > > VNC password auth scheme, as well as the VeNCrypt protocol extenion. The latter allows > > for performing a TLS handshake, and client verification of the server identify using > > x509 certificates. It is also possible for the server to request a client certificate > > and validate that as a simple auth scheme. The code depends on GNU TLS for SSL APIs, > > and the configure script will auto-detect this. > > Might be a stupid question as I don''t know what upstream QEMU VNC supports, > but would it make sense to add user+pass authentication support (via pam) ?This does not make much if any sense. There is no sensible mapping between host user accounts & guest virtual machine console access. If one were to add any further authentication to VNC, then it should be SASL based.> UltraVNC supports this, at least against Windows/AD users.That makes sense for UltraVNC because it is exposing the Windows desktop sessions for users. It does not make sense for QEMU because we''re not exposing any sessions associated with host users. Dan. -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel