--- vnc-4.0b5-javasrc/rfb/CSecurityVncAuth.java.tls 2004-06-11 12:12:30.000000000 +0100 +++ vnc-4.0b5-javasrc/rfb/CSecurityVncAuth.java 2004-06-11 12:12:44.000000000 +0100 @@ -31,12 +31,12 @@ StringBuffer passwd = new StringBuffer(); if (!upg.getUserPasswd(null, passwd)) { vlog.error("Getting password failed"); - return 0; + return MSG_ERROR; } VncAuth.encryptChallenge(challenge, passwd.toString()); os.writeBytes(challenge, 0, VncAuth.challengeSize); os.flush(); - return 1; + return MSG_COMPLETED; } public int getType() { return SecTypes.vncAuth; } --- vnc-4.0b5-javasrc/rfb/CConnection.java.tls 2004-06-11 12:11:20.000000000 +0100 +++ vnc-4.0b5-javasrc/rfb/CConnection.java 2004-06-11 12:53:57.426686357 +0100 @@ -22,7 +22,8 @@ public CConnection() { state_ = RFBSTATE_UNINITIALISED; - secTypes = new int[maxSecTypes]; + secTypes = new int[maxSecTypes]; + authTypes = new int[maxAuthTypes]; } // Methods to initialise the connection @@ -55,6 +56,12 @@ secTypes[nSecTypes++] = secType; } + public void addAuthType(int authType) { + if (nAuthTypes == maxAuthTypes) + throw new Exception("too many authentication types"); + authTypes[nAuthTypes++] = authType; + } + // setShared sets the value of the shared flag which will be sent to the // server upon initialisation. public void setShared(boolean s) { shared = s; } @@ -241,14 +248,68 @@ processSecurityMsg(); } + void processAuthTypesMsg() { + vlog.debug("processing authentication types message"); + + int authType = SecTypes.invalid; + + int nServerAuthTypes = is.readU8(); + if (nServerAuthTypes == 0) + throwConnFailedException(); + + int authTypePos = nAuthTypes; + for (int i = 0; i < nServerAuthTypes; i++) { + int serverAuthType = is.readU8(); + vlog.debug("Server offers authentication type "+ + SecTypes.name(serverAuthType)+"("+serverAuthType+")"); + + // If we haven't already chosen a authType, try this one + if (authType == SecTypes.invalid || clientSecTypeOrder ) { + for (int j = 0; j < nAuthTypes; j++) { + if (authTypes[j] == serverAuthType && j < authTypePos) { + authType = authTypes[j]; + authTypePos = j; + break; + } + } + // Continue reading the remaining server authTypes, but ignore them + } + } + + if (authType != SecTypes.invalid) { + os.writeU8(authType); + os.flush(); + vlog.debug("Choosing authentication type "+SecTypes.name(authType)+ + "("+authType+")"); + } + + if (authType == SecTypes.invalid) { + state_ = RFBSTATE_INVALID; + vlog.error("No matching authentication types"); + throw new Exception("No matching authentication types"); + } + + security = getCSecurity(authType); + processSecurityMsg(); + } + void processSecurityMsg() { vlog.debug("processing security message"); - int rc = security.processMsg(this); - if (rc == 0) + switch (security.processMsg(this)) { + case CSecurity.MSG_ERROR: throwAuthFailureException(); - if (rc == 1) { + break; + case CSecurity.MSG_COMPLETED: state_ = RFBSTATE_SECURITY_RESULT; processSecurityResultMsg(); + break; + case CSecurity.MSG_DEFER: + break; + case CSecurity.MSG_AUTH_TYPES: + processAuthTypesMsg(); + break; + default: + throw new Exception("CConnection.processMsg: invalid state"); } } @@ -317,8 +378,11 @@ boolean shared; CSecurity security; public static final int maxSecTypes = 8; + public static final int maxAuthTypes = 8; int nSecTypes; int[] secTypes; + int nAuthTypes; + int[] authTypes; int state_; String serverName; --- vnc-4.0b5-javasrc/rfb/CSecurity.java.tls 2004-06-11 12:11:20.000000000 +0100 +++ vnc-4.0b5-javasrc/rfb/CSecurity.java 2004-06-11 12:12:44.000000000 +0100 @@ -33,6 +33,11 @@ package rfb; abstract public class CSecurity { + public static final int MSG_ERROR = 0; + public static final int MSG_COMPLETED = 1; + public static final int MSG_DEFER = 2; + public static final int MSG_AUTH_TYPES = 3; + abstract public int processMsg(CConnection cc); abstract public int getType(); abstract public String description(); --- vnc-4.0b5-javasrc/rfb/CSecurityNone.java.tls 2004-06-11 12:12:10.000000000 +0100 +++ vnc-4.0b5-javasrc/rfb/CSecurityNone.java 2004-06-11 12:12:44.000000000 +0100 @@ -20,7 +20,7 @@ public class CSecurityNone extends CSecurity { public int processMsg(CConnection cc) { - return 1; + return MSG_COMPLETED; } public int getType() { return SecTypes.none; } public String description() { return "No Encryption"; } --- vnc-4.0b5-javasrc/rfb/SecTypes.java.tls 2004-06-11 12:12:34.000000000 +0100 +++ vnc-4.0b5-javasrc/rfb/SecTypes.java 2004-06-11 12:12:44.000000000 +0100 @@ -45,6 +45,7 @@ case vncAuth: return "VncAuth"; case RA2: return "RA2"; case RA2ne: return "RA2ne"; + case TLS: return "TLS"; default: return "[unknown secType]"; } } @@ -53,6 +54,7 @@ if (name.equalsIgnoreCase("VncAuth")) return vncAuth; if (name.equalsIgnoreCase("RA2")) return RA2; if (name.equalsIgnoreCase("RA2ne")) return RA2ne; + if (name.equalsIgnoreCase("TLS")) return TLS; return invalid; } //std::list parseSecTypes(const char* types); --- vnc-4.0b5-javasrc/rfb/CSecurityTLS.java.tls 2004-06-11 12:12:25.000000000 +0100 +++ vnc-4.0b5-javasrc/rfb/CSecurityTLS.java 2004-06-11 12:14:05.000000000 +0100 @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2003 Sun Microsystems, Inc. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +package rfb; + +import java.util.ArrayList; +import java.net.*; +import javax.net.ssl.*; + +public class CSecurityTLS extends CSecurity { + + public CSecurityTLS(Socket sock_) { + sock = sock_; + } + + public int processMsg(CConnection cc) { + try { + SSLSocketFactory sslfactory; + SSLSocket sslsock; + + sslfactory = (SSLSocketFactory)SSLSocketFactory.getDefault(); + sslsock = (SSLSocket)sslfactory.createSocket (sock, + sock.getInetAddress().getHostName(), + sock.getPort(), + true); + + setAnonDHKeyExchangeEnabled(sslsock); + + /* Not neccessary - just ensures that we know what cipher + * suite we are using for the output of toString() + */ + sslsock.startHandshake(); + + tlog.debug("Completed handshake with server " + sslsock.toString ()); + + cc.setStreams(new rdr.JavaInStream(sslsock.getInputStream()), + new rdr.JavaOutStream(sslsock.getOutputStream())); + + return MSG_AUTH_TYPES; + } catch (java.io.IOException e) { + tlog.error("TLS handshake failed " + e.toString()); + return MSG_ERROR; + } + } + + private static void setAnonDHKeyExchangeEnabled(SSLSocket sock) { + String[] supported; + ArrayList enabled = new ArrayList(); + + supported = sock.getSupportedCipherSuites(); + + for (int i = 0; i < supported.length; i++) + if (supported [i].matches(".*DH_anon.*")) + enabled.add(supported [i]); + + sock.setEnabledCipherSuites((String[])enabled.toArray(new String[0])); + } + + public int getType() { return SecTypes.TLS; } + public String description() { return "TLS Encryption"; } + + Socket sock; + + static LogWriter tlog = new LogWriter("TLS"); +} --- vnc-4.0b5-javasrc/vncviewer/CConn.java.tls 2004-06-11 12:12:38.000000000 +0100 +++ vnc-4.0b5-javasrc/vncviewer/CConn.java 2004-06-11 12:12:44.000000000 +0100 @@ -84,8 +84,14 @@ clipboardDialog = new ClipboardDialog(this); setShared(shared); + + addSecType(rfb.SecTypes.TLS); addSecType(rfb.SecTypes.none); addSecType(rfb.SecTypes.vncAuth); + + addAuthType(rfb.SecTypes.none); + addAuthType(rfb.SecTypes.vncAuth); + String encStr = viewer.preferredEncoding.getValue(); if (encStr != null) { int encNum = rfb.Encodings.num(encStr); @@ -127,9 +133,8 @@ } setServerName(sock.getInetAddress().getHostAddress()+"::"+sock.getPort()); - jis = new rdr.JavaInStream(sock.getInputStream()); - jos = new rdr.JavaOutStream(sock.getOutputStream()); - setStreams(jis, jos); + setStreams(new rdr.JavaInStream(sock.getInputStream()), + new rdr.JavaOutStream(sock.getOutputStream())); initialiseProtocol(); return true; } @@ -162,20 +167,33 @@ // types which we support. public rfb.CSecurity getCSecurity(int secType) { + rfb.CSecurity security; + switch (secType) { case rfb.SecTypes.none: - return new rfb.CSecurityNone(); + security = new rfb.CSecurityNone(); + break; case rfb.SecTypes.vncAuth: - return new rfb.CSecurityVncAuth(this); + security = new rfb.CSecurityVncAuth(this); + break; + case rfb.SecTypes.TLS: + security = new rfb.CSecurityTLS(this.sock); + break; default: throw new rfb.Exception("Unsupported secType?"); } + + vlog.info("Using security type '" + security.description() + "'"); + + return security; } // serverInit() is called when the serverInit message has been received. At // this point we create the desktop window and display it. We also tell the // server the pixel format and encodings to use and request the first update. public void serverInit() { + jis = (rdr.JavaInStream)getInStream(); + jos = (rdr.JavaOutStream)getOutStream(); super.serverInit(); serverPF = cp.pf(); desktop = new DesktopWindow(serverPF, this);