diff options
Diffstat (limited to 'webclients/java-applet/ssl/tightvnc-1.3dev7_javasrc-vncviewer-ssl.patch')
-rw-r--r-- | webclients/java-applet/ssl/tightvnc-1.3dev7_javasrc-vncviewer-ssl.patch | 2600 |
1 files changed, 2600 insertions, 0 deletions
diff --git a/webclients/java-applet/ssl/tightvnc-1.3dev7_javasrc-vncviewer-ssl.patch b/webclients/java-applet/ssl/tightvnc-1.3dev7_javasrc-vncviewer-ssl.patch new file mode 100644 index 0000000..801234a --- /dev/null +++ b/webclients/java-applet/ssl/tightvnc-1.3dev7_javasrc-vncviewer-ssl.patch @@ -0,0 +1,2600 @@ +diff -Naur vnc_javasrc.orig/Makefile vnc_javasrc/Makefile +--- vnc_javasrc.orig/Makefile 2004-03-04 08:34:25.000000000 -0500 ++++ vnc_javasrc/Makefile 2010-05-18 20:56:26.000000000 -0400 +@@ -4,6 +4,7 @@ + + CP = cp + JC = javac ++JC_ARGS = -target 1.4 -source 1.4 + JAR = jar + ARCHIVE = VncViewer.jar + MANIFEST = MANIFEST.MF +@@ -15,25 +16,29 @@ + DesCipher.class CapabilityInfo.class CapsContainer.class \ + RecordingFrame.class SessionRecorder.class AuthUnixLoginPanel.class \ + SocketFactory.class HTTPConnectSocketFactory.class \ +- HTTPConnectSocket.class ReloginPanel.class ++ HTTPConnectSocket.class ReloginPanel.class \ ++ SSLSocketToMe.class ++ ++SSL_CLASSES = SSLSocketToMe*.class TrustDialog.class + + SOURCES = VncViewer.java RfbProto.java AuthPanel.java VncCanvas.java \ + OptionsFrame.java ClipboardFrame.java ButtonPanel.java \ + DesCipher.java CapabilityInfo.java CapsContainer.java \ + RecordingFrame.java SessionRecorder.java AuthUnixLoginPanel.java \ + SocketFactory.java HTTPConnectSocketFactory.java \ +- HTTPConnectSocket.java ReloginPanel.java ++ HTTPConnectSocket.java ReloginPanel.java \ ++ SSLSocketToMe.java + + all: $(CLASSES) $(ARCHIVE) + + $(CLASSES): $(SOURCES) +- $(JC) -target 1.1 -O $(SOURCES) ++ $(JC) $(JC_ARGS) -O $(SOURCES) + + $(ARCHIVE): $(CLASSES) $(MANIFEST) +- $(JAR) cfm $(ARCHIVE) $(MANIFEST) $(CLASSES) ++ $(JAR) cfm $(ARCHIVE) $(MANIFEST) $(CLASSES) $(SSL_CLASSES) + + install: $(CLASSES) $(ARCHIVE) +- $(CP) $(CLASSES) $(ARCHIVE) $(PAGES) $(INSTALL_DIR) ++ $(CP) $(CLASSES) $(SSL_CLASSES) $(ARCHIVE) $(PAGES) $(INSTALL_DIR) + + export:: $(CLASSES) $(ARCHIVE) $(PAGES) + @$(ExportJavaClasses) +diff -Naur vnc_javasrc.orig/RfbProto.java vnc_javasrc/RfbProto.java +--- vnc_javasrc.orig/RfbProto.java 2004-03-04 08:34:25.000000000 -0500 ++++ vnc_javasrc/RfbProto.java 2010-11-30 22:05:12.000000000 -0500 +@@ -199,7 +199,21 @@ + host = h; + port = p; + +- if (viewer.socketFactory == null) { ++ if (! viewer.disableSSL) { ++ System.out.println("new SSLSocketToMe"); ++ SSLSocketToMe ssl; ++ try { ++ ssl = new SSLSocketToMe(host, port, v); ++ } catch (Exception e) { ++ throw new IOException(e.getMessage()); ++ } ++ ++ try { ++ sock = ssl.connectSock(); ++ } catch (Exception es) { ++ throw new IOException(es.getMessage()); ++ } ++ } else if (viewer.socketFactory == null) { + sock = new Socket(host, port); + } else { + try { +@@ -255,7 +269,7 @@ + || (b[10] < '0') || (b[10] > '9') || (b[11] != '\n')) + { + throw new Exception("Host " + host + " port " + port + +- " is not an RFB server"); ++ " is not an RFB server: " + b); + } + + serverMajor = (b[4] - '0') * 100 + (b[5] - '0') * 10 + (b[6] - '0'); +@@ -892,6 +906,38 @@ + final static int ALT_MASK = InputEvent.ALT_MASK; + + ++ void writeWheelEvent(MouseWheelEvent evt) throws IOException { ++ ++ eventBufLen = 0; ++ ++ int x = evt.getX(); ++ int y = evt.getY(); ++ ++ if (x < 0) x = 0; ++ if (y < 0) y = 0; ++ ++ int ptrmask; ++ ++ int clicks = evt.getWheelRotation(); ++ System.out.println("writeWheelEvent: clicks: " + clicks); ++ if (clicks > 0) { ++ ptrmask = 16; ++ } else if (clicks < 0) { ++ ptrmask = 8; ++ } else { ++ return; ++ } ++ ++ eventBuf[eventBufLen++] = (byte) PointerEvent; ++ eventBuf[eventBufLen++] = (byte) ptrmask; ++ eventBuf[eventBufLen++] = (byte) ((x >> 8) & 0xff); ++ eventBuf[eventBufLen++] = (byte) (x & 0xff); ++ eventBuf[eventBufLen++] = (byte) ((y >> 8) & 0xff); ++ eventBuf[eventBufLen++] = (byte) (y & 0xff); ++ ++ os.write(eventBuf, 0, eventBufLen); ++ } ++ + // + // Write a pointer event message. We may need to send modifier key events + // around it to set the correct modifier state. +@@ -992,6 +1038,19 @@ + boolean down = (evt.getID() == KeyEvent.KEY_PRESSED); + + int key; ++ if (viewer.debugKeyboard) { ++ System.out.println("----------------------------------------"); ++ System.out.println("evt.getKeyChar: " + evt.getKeyChar()); ++ System.out.println("getKeyText: " + KeyEvent.getKeyText(evt.getKeyCode())); ++ System.out.println("evt.getKeyCode: " + evt.getKeyCode()); ++ System.out.println("evt.getID: " + evt.getID()); ++ System.out.println("evt.getKeyLocation: " + evt.getKeyLocation()); ++ System.out.println("evt.isActionKey: " + evt.isActionKey()); ++ System.out.println("evt.isControlDown: " + evt.isControlDown()); ++ System.out.println("evt.getModifiers: " + evt.getModifiers()); ++ System.out.println("getKeyModifiersText: " + KeyEvent.getKeyModifiersText(evt.getModifiers())); ++ System.out.println("evt.paramString: " + evt.paramString()); ++ } + if (evt.isActionKey()) { + + // +@@ -1025,6 +1084,13 @@ + return; + } + ++ if(key == 0xffc2 && viewer.mapF5_to_atsign) { ++ if (viewer.debugKeyboard) { ++ System.out.println("Mapping: F5 -> AT "); ++ } ++ key = 0x40; ++ } ++ + } else { + + // +@@ -1036,6 +1102,7 @@ + + key = keyChar; + ++ + if (key < 0x20) { + if (evt.isControlDown()) { + key += 0x60; +@@ -1121,6 +1188,16 @@ + int oldModifiers = 0; + + void writeModifierKeyEvents(int newModifiers) { ++ if(viewer.forbid_Ctrl_Alt) { ++ if ((newModifiers & CTRL_MASK) != 0 && (newModifiers & ALT_MASK) != 0) { ++ int orig = newModifiers; ++ newModifiers &= ~ALT_MASK; ++ newModifiers &= ~CTRL_MASK; ++ if (viewer.debugKeyboard) { ++ System.out.println("Ctrl+Alt modifiers: " + orig + " -> " + newModifiers); ++ } ++ } ++ } + if ((newModifiers & CTRL_MASK) != (oldModifiers & CTRL_MASK)) + writeKeyEvent(0xffe3, (newModifiers & CTRL_MASK) != 0); + +diff -Naur vnc_javasrc.orig/SSLSocketToMe.java vnc_javasrc/SSLSocketToMe.java +--- vnc_javasrc.orig/SSLSocketToMe.java 1969-12-31 19:00:00.000000000 -0500 ++++ vnc_javasrc/SSLSocketToMe.java 2010-07-10 19:18:06.000000000 -0400 +@@ -0,0 +1,2067 @@ ++/* ++ * SSLSocketToMe.java: add SSL encryption to Java VNC Viewer. ++ * ++ * Copyright (c) 2006 Karl J. Runge <[email protected]> ++ * All rights reserved. ++ * ++ * 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; 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. ++ * ++ */ ++ ++import java.net.*; ++import java.io.*; ++import javax.net.ssl.*; ++import java.util.*; ++ ++import java.security.*; ++import java.security.cert.*; ++import java.security.spec.*; ++import java.security.cert.Certificate; ++import java.security.cert.CertificateFactory; ++ ++import java.awt.*; ++import java.awt.event.*; ++ ++public class SSLSocketToMe { ++ ++ /* basic member data: */ ++ String host; ++ int port; ++ VncViewer viewer; ++ ++ boolean debug = true; ++ boolean debug_certs = false; ++ ++ /* sockets */ ++ SSLSocket socket = null; ++ SSLSocketFactory factory; ++ ++ /* fallback for Proxy connection */ ++ boolean proxy_in_use = false; ++ boolean proxy_failure = false; ++ public DataInputStream is = null; ++ public OutputStream os = null; ++ ++ /* strings from user WRT proxy: */ ++ String proxy_auth_string = null; ++ String proxy_dialog_host = null; ++ int proxy_dialog_port = 0; ++ ++ Socket proxySock; ++ DataInputStream proxy_is; ++ OutputStream proxy_os; ++ ++ /* trust contexts */ ++ SSLContext trustloc_ctx; ++ SSLContext trustall_ctx; ++ SSLContext trustsrv_ctx; ++ SSLContext trusturl_ctx; ++ SSLContext trustone_ctx; ++ ++ /* corresponding trust managers */ ++ TrustManager[] trustAllCerts; ++ TrustManager[] trustSrvCert; ++ TrustManager[] trustUrlCert; ++ TrustManager[] trustOneCert; ++ ++ /* client-side SSL auth key (oneTimeKey=...) */ ++ KeyManager[] mykey = null; ++ ++ boolean user_wants_to_see_cert = true; ++ String cert_fail = null; ++ ++ /* cert(s) we retrieve from Web server, VNC server, or serverCert param: */ ++ java.security.cert.Certificate[] trustallCerts = null; ++ java.security.cert.Certificate[] trustsrvCerts = null; ++ java.security.cert.Certificate[] trusturlCerts = null; ++ ++ /* utility to decode hex oneTimeKey=... and serverCert=... */ ++ byte[] hex2bytes(String s) { ++ byte[] bytes = new byte[s.length()/2]; ++ for (int i=0; i<s.length()/2; i++) { ++ int j = 2*i; ++ try { ++ int val = Integer.parseInt(s.substring(j, j+2), 16); ++ if (val > 127) { ++ val -= 256; ++ } ++ Integer I = new Integer(val); ++ bytes[i] = Byte.decode(I.toString()).byteValue(); ++ ++ } catch (Exception e) { ++ ; ++ } ++ } ++ return bytes; ++ } ++ ++ SSLSocketToMe(String h, int p, VncViewer v) throws Exception { ++ host = h; ++ port = p; ++ viewer = v; ++ ++ debug_certs = v.debugCerts; ++ ++ /* we will first try default factory for certification: */ ++ ++ factory = (SSLSocketFactory) SSLSocketFactory.getDefault(); ++ ++ dbg("SSL startup: " + host + " " + port); ++ ++ ++ /* create trust managers to be used if initial handshake fails: */ ++ ++ trustAllCerts = new TrustManager[] { ++ /* ++ * this one accepts everything. Only used if user ++ * has disabled checking (trustAllVncCerts=yes) ++ * or when we grab the cert to show it to them in ++ * a dialog and ask them to manually verify/accept it. ++ */ ++ new X509TrustManager() { ++ public java.security.cert.X509Certificate[] ++ getAcceptedIssuers() { ++ return null; ++ } ++ public void checkClientTrusted( ++ java.security.cert.X509Certificate[] certs, ++ String authType) { ++ /* empty */ ++ } ++ public void checkServerTrusted( ++ java.security.cert.X509Certificate[] certs, ++ String authType) { ++ /* empty */ ++ dbg("ALL: an untrusted connect to grab cert."); ++ } ++ } ++ }; ++ ++ trustUrlCert = new TrustManager[] { ++ /* ++ * this one accepts only the retrieved server ++ * cert by SSLSocket by this applet and stored in ++ * trusturlCerts. ++ */ ++ new X509TrustManager() { ++ public java.security.cert.X509Certificate[] ++ getAcceptedIssuers() { ++ return null; ++ } ++ public void checkClientTrusted( ++ java.security.cert.X509Certificate[] certs, ++ String authType) throws CertificateException { ++ throw new CertificateException("No Clients (URL)"); ++ } ++ public void checkServerTrusted( ++ java.security.cert.X509Certificate[] certs, ++ String authType) throws CertificateException { ++ /* we want to check 'certs' against 'trusturlCerts' */ ++ if (trusturlCerts == null) { ++ throw new CertificateException( ++ "No Trust url Certs array."); ++ } ++ if (trusturlCerts.length < 1) { ++ throw new CertificateException( ++ "No Trust url Certs."); ++ } ++ if (certs == null) { ++ throw new CertificateException( ++ "No this-certs array."); ++ } ++ if (certs.length < 1) { ++ throw new CertificateException( ++ "No this-certs Certs."); ++ } ++ if (certs.length != trusturlCerts.length) { ++ throw new CertificateException( ++ "certs.length != trusturlCerts.length " + certs.length + " " + trusturlCerts.length); ++ } ++ boolean ok = true; ++ for (int i = 0; i < certs.length; i++) { ++ if (! trusturlCerts[i].equals(certs[i])) { ++ ok = false; ++ dbg("URL: cert mismatch at i=" + i); ++ dbg("URL: cert mismatch cert" + certs[i]); ++ dbg("URL: cert mismatch url" + trusturlCerts[i]); ++ if (cert_fail == null) { ++ cert_fail = "cert-mismatch"; ++ } ++ } ++ if (debug_certs) { ++ dbg("\n***********************************************"); ++ dbg("URL: cert info at i=" + i); ++ dbg("URL: cert info cert" + certs[i]); ++ dbg("==============================================="); ++ dbg("URL: cert info url" + trusturlCerts[i]); ++ dbg("***********************************************"); ++ } ++ } ++ if (!ok) { ++ throw new CertificateException( ++ "Server Cert Chain != URL Cert Chain."); ++ } ++ dbg("URL: trusturlCerts[i] matches certs[i] i=0:" + (certs.length-1)); ++ } ++ } ++ }; ++ ++ trustSrvCert = new TrustManager[] { ++ /* ++ * this one accepts cert given to us in the serverCert ++ * Applet Parameter we were started with. It is ++ * currently a fatal error if the VNC Server's cert ++ * doesn't match it. ++ */ ++ new X509TrustManager() { ++ public java.security.cert.X509Certificate[] ++ getAcceptedIssuers() { ++ return null; ++ } ++ public void checkClientTrusted( ++ java.security.cert.X509Certificate[] certs, ++ String authType) throws CertificateException { ++ throw new CertificateException("No Clients (SRV)"); ++ } ++ public void checkServerTrusted( ++ java.security.cert.X509Certificate[] certs, ++ String authType) throws CertificateException { ++ /* we want to check 'certs' against 'trustsrvCerts' */ ++ if (trustsrvCerts == null) { ++ throw new CertificateException( ++ "No Trust srv Certs array."); ++ } ++ if (trustsrvCerts.length < 1) { ++ throw new CertificateException( ++ "No Trust srv Certs."); ++ } ++ if (certs == null) { ++ throw new CertificateException( ++ "No this-certs array."); ++ } ++ if (certs.length < 1) { ++ throw new CertificateException( ++ "No this-certs Certs."); ++ } ++ if (certs.length != trustsrvCerts.length) { ++ throw new CertificateException( ++ "certs.length != trustsrvCerts.length " + certs.length + " " + trustsrvCerts.length); ++ } ++ boolean ok = true; ++ for (int i = 0; i < certs.length; i++) { ++ if (! trustsrvCerts[i].equals(certs[i])) { ++ ok = false; ++ dbg("SRV: cert mismatch at i=" + i); ++ dbg("SRV: cert mismatch cert" + certs[i]); ++ dbg("SRV: cert mismatch srv" + trustsrvCerts[i]); ++ if (cert_fail == null) { ++ cert_fail = "server-cert-mismatch"; ++ } ++ } ++ if (debug_certs) { ++ dbg("\n***********************************************"); ++ dbg("SRV: cert info at i=" + i); ++ dbg("SRV: cert info cert" + certs[i]); ++ dbg("==============================================="); ++ dbg("SRV: cert info srv" + trustsrvCerts[i]); ++ dbg("***********************************************"); ++ } ++ } ++ if (!ok) { ++ throw new CertificateException( ++ "Server Cert Chain != serverCert Applet Parameter Cert Chain."); ++ } ++ dbg("SRV: trustsrvCerts[i] matches certs[i] i=0:" + (certs.length-1)); ++ } ++ } ++ }; ++ ++ trustOneCert = new TrustManager[] { ++ /* ++ * this one accepts only the retrieved server ++ * cert by SSLSocket by this applet we stored in ++ * trustallCerts that user has accepted or applet ++ * parameter trustAllVncCerts=yes is set. This is ++ * for when we reconnect after the user has manually ++ * accepted the trustall cert in the dialog (or set ++ * trustAllVncCerts=yes applet param.) ++ */ ++ new X509TrustManager() { ++ public java.security.cert.X509Certificate[] ++ getAcceptedIssuers() { ++ return null; ++ } ++ public void checkClientTrusted( ++ java.security.cert.X509Certificate[] certs, ++ String authType) throws CertificateException { ++ throw new CertificateException("No Clients (ONE)"); ++ } ++ public void checkServerTrusted( ++ java.security.cert.X509Certificate[] certs, ++ String authType) throws CertificateException { ++ /* we want to check 'certs' against 'trustallCerts' */ ++ if (trustallCerts == null) { ++ throw new CertificateException( ++ "No Trust All Server Certs array."); ++ } ++ if (trustallCerts.length < 1) { ++ throw new CertificateException( ++ "No Trust All Server Certs."); ++ } ++ if (certs == null) { ++ throw new CertificateException( ++ "No this-certs array."); ++ } ++ if (certs.length < 1) { ++ throw new CertificateException( ++ "No this-certs Certs."); ++ } ++ if (certs.length != trustallCerts.length) { ++ throw new CertificateException( ++ "certs.length != trustallCerts.length " + certs.length + " " + trustallCerts.length); ++ } ++ boolean ok = true; ++ for (int i = 0; i < certs.length; i++) { ++ if (! trustallCerts[i].equals(certs[i])) { ++ ok = false; ++ dbg("ONE: cert mismatch at i=" + i); ++ dbg("ONE: cert mismatch cert" + certs[i]); ++ dbg("ONE: cert mismatch all" + trustallCerts[i]); ++ } ++ if (debug_certs) { ++ dbg("\n***********************************************"); ++ dbg("ONE: cert info at i=" + i); ++ dbg("ONE: cert info cert" + certs[i]); ++ dbg("==============================================="); ++ dbg("ONE: cert info all" + trustallCerts[i]); ++ dbg("***********************************************"); ++ } ++ } ++ if (!ok) { ++ throw new CertificateException( ++ "Server Cert Chain != TRUSTALL Cert Chain."); ++ } ++ dbg("ONE: trustallCerts[i] matches certs[i] i=0:" + (certs.length-1)); ++ } ++ } ++ }; ++ ++ /* ++ * The above TrustManagers are used: ++ * ++ * 1) to retrieve the server cert in case of failure to ++ * display it to the user in a dialog. ++ * 2) to subsequently connect to the server if user agrees. ++ */ ++ ++ /* ++ * build oneTimeKey cert+key if supplied in applet parameter: ++ */ ++ if (viewer.oneTimeKey != null && viewer.oneTimeKey.equals("PROMPT")) { ++ ClientCertDialog d = new ClientCertDialog(); ++ viewer.oneTimeKey = d.queryUser(); ++ } ++ if (viewer.oneTimeKey != null && viewer.oneTimeKey.indexOf(",") > 0) { ++ int idx = viewer.oneTimeKey.indexOf(","); ++ ++ String onetimekey = viewer.oneTimeKey.substring(0, idx); ++ byte[] key = hex2bytes(onetimekey); ++ String onetimecert = viewer.oneTimeKey.substring(idx+1); ++ byte[] cert = hex2bytes(onetimecert); ++ ++ KeyFactory kf = KeyFactory.getInstance("RSA"); ++ PKCS8EncodedKeySpec keysp = new PKCS8EncodedKeySpec ( key ); ++ PrivateKey ff = kf.generatePrivate (keysp); ++ if (debug_certs) { ++ dbg("one time key " + ff); ++ } ++ ++ CertificateFactory cf = CertificateFactory.getInstance("X.509"); ++ Collection c = cf.generateCertificates(new ByteArrayInputStream(cert)); ++ Certificate[] certs = new Certificate[c.toArray().length]; ++ if (c.size() == 1) { ++ Certificate tmpcert = cf.generateCertificate(new ByteArrayInputStream(cert)); ++ if (debug_certs) { ++ dbg("one time cert" + tmpcert); ++ } ++ certs[0] = tmpcert; ++ } else { ++ certs = (Certificate[]) c.toArray(); ++ } ++ ++ KeyStore ks = KeyStore.getInstance("JKS"); ++ ks.load(null, null); ++ ks.setKeyEntry("onetimekey", ff, "".toCharArray(), certs); ++ String da = KeyManagerFactory.getDefaultAlgorithm(); ++ KeyManagerFactory kmf = KeyManagerFactory.getInstance(da); ++ kmf.init(ks, "".toCharArray()); ++ ++ mykey = kmf.getKeyManagers(); ++ } ++ ++ /* ++ * build serverCert cert if supplied in applet parameter: ++ */ ++ if (viewer.serverCert != null) { ++ CertificateFactory cf = CertificateFactory.getInstance("X.509"); ++ byte[] cert = hex2bytes(viewer.serverCert); ++ Collection c = cf.generateCertificates(new ByteArrayInputStream(cert)); ++ trustsrvCerts = new Certificate[c.toArray().length]; ++ if (c.size() == 1) { ++ Certificate tmpcert = cf.generateCertificate(new ByteArrayInputStream(cert)); ++ trustsrvCerts[0] = tmpcert; ++ } else { ++ trustsrvCerts = (Certificate[]) c.toArray(); ++ } ++ } ++ ++ /* the trust loc certs context: */ ++ try { ++ trustloc_ctx = SSLContext.getInstance("SSL"); ++ ++ /* ++ * below is a failed attempt to get jvm's default ++ * trust manager using null (below) makes it so ++ * for HttpsURLConnection the server cannot be ++ * verified (no prompting.) ++ */ ++ if (false) { ++ boolean didit = false; ++ TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); ++ tmf.init((KeyStore) null); ++ TrustManager [] tml = tmf.getTrustManagers(); ++ for (int i = 0; i < tml.length; i++) { ++ TrustManager tm = tml[i]; ++ if (tm instanceof X509TrustManager) { ++ TrustManager tm1[] = new TrustManager[1]; ++ tm1[0] = tm; ++ trustloc_ctx.init(mykey, tm1, null); ++ didit = true; ++ break; ++ } ++ } ++ if (!didit) { ++ trustloc_ctx.init(mykey, null, null); ++ } ++ } else { ++ /* we have to set trust manager to null */ ++ trustloc_ctx.init(mykey, null, null); ++ } ++ ++ } catch (Exception e) { ++ String msg = "SSL trustloc_ctx FAILED."; ++ dbg(msg); ++ throw new Exception(msg); ++ } ++ ++ /* the trust all certs context: */ ++ try { ++ trustall_ctx = SSLContext.getInstance("SSL"); ++ trustall_ctx.init(mykey, trustAllCerts, new ++ java.security.SecureRandom()); ++ ++ } catch (Exception e) { ++ String msg = "SSL trustall_ctx FAILED."; ++ dbg(msg); ++ throw new Exception(msg); ++ } ++ ++ /* the trust url certs context: */ ++ try { ++ trusturl_ctx = SSLContext.getInstance("SSL"); ++ trusturl_ctx.init(mykey, trustUrlCert, new ++ java.security.SecureRandom()); ++ ++ } catch (Exception e) { ++ String msg = "SSL trusturl_ctx FAILED."; ++ dbg(msg); ++ throw new Exception(msg); ++ } ++ ++ /* the trust srv certs context: */ ++ try { ++ trustsrv_ctx = SSLContext.getInstance("SSL"); ++ trustsrv_ctx.init(mykey, trustSrvCert, new ++ java.security.SecureRandom()); ++ ++ } catch (Exception e) { ++ String msg = "SSL trustsrv_ctx FAILED."; ++ dbg(msg); ++ throw new Exception(msg); ++ } ++ ++ /* the trust the one cert from server context: */ ++ try { ++ trustone_ctx = SSLContext.getInstance("SSL"); ++ trustone_ctx.init(mykey, trustOneCert, new ++ java.security.SecureRandom()); ++ ++ } catch (Exception e) { ++ String msg = "SSL trustone_ctx FAILED."; ++ dbg(msg); ++ throw new Exception(msg); ++ } ++ } ++ ++ /* ++ * we call this early on to 1) check for a proxy, 2) grab ++ * Browser/JVM accepted HTTPS cert. ++ */ ++ public void check_for_proxy_and_grab_vnc_server_cert() { ++ ++ trusturlCerts = null; ++ proxy_in_use = false; ++ ++ if (viewer.ignoreProxy) { ++ /* applet param says skip it. */ ++ /* the downside is we do not set trusturlCerts for comparison later... */ ++ /* nor do we autodetect x11vnc for GET=1. */ ++ return; ++ } ++ ++ dbg("------------------------------------------------"); ++ dbg("Into check_for_proxy_and_grab_vnc_server_cert():"); ++ ++ dbg("TRYING HTTPS:"); ++ String ustr = "https://" + host + ":"; ++ if (viewer.httpsPort != null) { ++ ustr += viewer.httpsPort; ++ } else { ++ ustr += port; ++ } ++ ustr += viewer.urlPrefix + "/check.https.proxy.connection"; ++ dbg("ustr is: " + ustr); ++ ++ try { ++ /* prepare for an HTTPS URL connection to host:port */ ++ URL url = new URL(ustr); ++ HttpsURLConnection https = (HttpsURLConnection) url.openConnection(); ++ ++ if (mykey != null) { ++ /* with oneTimeKey (mykey) we can't use the default SSL context */ ++ if (trustsrvCerts != null) { ++ dbg("passing trustsrv_ctx to HttpsURLConnection to provide client cert."); ++ https.setSSLSocketFactory(trustsrv_ctx.getSocketFactory()); ++ } else if (trustloc_ctx != null) { ++ dbg("passing trustloc_ctx to HttpsURLConnection to provide client cert."); ++ https.setSSLSocketFactory(trustloc_ctx.getSocketFactory()); ++ } ++ } ++ ++ https.setUseCaches(false); ++ https.setRequestMethod("GET"); ++ https.setRequestProperty("Pragma", "No-Cache"); ++ https.setRequestProperty("Proxy-Connection", "Keep-Alive"); ++ https.setDoInput(true); ++ ++ dbg("trying https.connect()"); ++ https.connect(); ++ ++ dbg("trying https.getServerCertificates()"); ++ trusturlCerts = https.getServerCertificates(); ++ ++ if (trusturlCerts == null) { ++ dbg("set trusturlCerts to null!"); ++ } else { ++ dbg("set trusturlCerts to non-null"); ++ } ++ ++ if (https.usingProxy()) { ++ proxy_in_use = true; ++ dbg("An HTTPS proxy is in use. There may be connection problems."); ++ } ++ ++ dbg("trying https.getContent()"); ++ Object output = https.getContent(); ++ dbg("trying https.disconnect()"); ++ https.disconnect(); ++ if (! viewer.GET) { ++ String header = https.getHeaderField("VNC-Server"); ++ if (header != null && header.startsWith("x11vnc")) { ++ dbg("detected x11vnc server (1), setting GET=1"); ++ viewer.GET = true; ++ } ++ } ++ ++ } catch(Exception e) { ++ dbg("HttpsURLConnection: " + e.getMessage()); ++ } ++ ++ if (proxy_in_use) { ++ dbg("exit check_for_proxy_and_grab_vnc_server_cert():"); ++ dbg("------------------------------------------------"); ++ return; ++ } else if (trusturlCerts != null && !viewer.forceProxy) { ++ /* Allow user to require HTTP check? use forceProxy for now. */ ++ dbg("SKIPPING HTTP PROXY CHECK: got trusturlCerts, assuming proxy info is correct."); ++ dbg("exit check_for_proxy_and_grab_vnc_server_cert():"); ++ dbg("------------------------------------------------"); ++ return; ++ } ++ ++ /* ++ * XXX need to remember scenario where this extra check ++ * gives useful info. User's Browser proxy settings? ++ */ ++ dbg("TRYING HTTP:"); ++ ustr = "http://" + host + ":" + port; ++ ustr += viewer.urlPrefix + "/index.vnc"; ++ dbg("ustr is: " + ustr); ++ ++ try { ++ /* prepare for an HTTP URL connection to the same host:port (but not httpsPort) */ ++ URL url = new URL(ustr); ++ HttpURLConnection http = (HttpURLConnection) ++ url.openConnection(); ++ ++ http.setUseCaches(false); ++ http.setRequestMethod("GET"); ++ http.setRequestProperty("Pragma", "No-Cache"); ++ http.setRequestProperty("Proxy-Connection", "Keep-Alive"); ++ http.setDoInput(true); ++ ++ dbg("trying http.connect()"); ++ http.connect(); ++ ++ if (http.usingProxy()) { ++ proxy_in_use = true; ++ dbg("An HTTP proxy is in use. There may be connection problems."); ++ } ++ dbg("trying http.getContent()"); ++ Object output = http.getContent(); ++ dbg("trying http.disconnect()"); ++ http.disconnect(); ++ if (! viewer.GET) { ++ String header = http.getHeaderField("VNC-Server"); ++ if (header != null && header.startsWith("x11vnc")) { ++ dbg("detected x11vnc server (2), setting GET=1"); ++ viewer.GET = true; ++ } ++ } ++ } catch(Exception e) { ++ dbg("HttpURLConnection: " + e.getMessage()); ++ } ++ dbg("exit check_for_proxy_and_grab_vnc_server_cert():"); ++ dbg("------------------------------------------------"); ++ } ++ ++ public Socket connectSock() throws IOException { ++ /* ++ * first try a https connection to detect a proxy, and ++ * grab the VNC server cert at the same time: ++ */ ++ check_for_proxy_and_grab_vnc_server_cert(); ++ ++ boolean srv_cert = false; ++ ++ if (trustsrvCerts != null) { ++ /* applet parameter suppled serverCert */ ++ dbg("viewer.trustSrvCert-0 using trustsrv_ctx"); ++ factory = trustsrv_ctx.getSocketFactory(); ++ srv_cert = true; ++ } else if (viewer.trustAllVncCerts) { ++ /* trust all certs (no checking) */ ++ dbg("viewer.trustAllVncCerts-0 using trustall_ctx"); ++ factory = trustall_ctx.getSocketFactory(); ++ } else if (trusturlCerts != null) { ++ /* trust certs the Browser/JVM accepted in check_for_proxy... */ ++ dbg("using trusturl_ctx"); ++ factory = trusturl_ctx.getSocketFactory(); ++ } else { ++ /* trust the local defaults */ ++ dbg("using trustloc_ctx"); ++ factory = trustloc_ctx.getSocketFactory(); ++ } ++ ++ socket = null; ++ ++ try { ++ if (proxy_in_use && viewer.forceProxy) { ++ throw new Exception("forcing proxy (forceProxy)"); ++ } else if (viewer.CONNECT != null) { ++ throw new Exception("forcing CONNECT"); ++ } ++ ++ int timeout = 6; ++ if (timeout > 0) { ++ socket = (SSLSocket) factory.createSocket(); ++ InetSocketAddress inetaddr = new InetSocketAddress(host, port); ++ dbg("Using timeout of " + timeout + " secs to: " + host + ":" + port); ++ socket.connect(inetaddr, timeout * 1000); ++ } else { ++ socket = (SSLSocket) factory.createSocket(host, port); ++ } ++ ++ } catch (Exception esock) { ++ dbg("socket error: " + esock.getMessage()); ++ if (proxy_in_use || viewer.CONNECT != null) { ++ proxy_failure = true; ++ if (proxy_in_use) { ++ dbg("HTTPS proxy in use. Trying to go with it."); ++ } else { ++ dbg("viewer.CONNECT reverse proxy in use. Trying to go with it."); ++ } ++ try { ++ socket = proxy_socket(factory); ++ } catch (Exception e) { ++ dbg("proxy_socket error: " + e.getMessage()); ++ } ++ } else { ++ /* n.b. socket is left in error state to cause ex. below. */ ++ } ++ } ++ ++ try { ++ socket.startHandshake(); ++ ++ dbg("The Server Connection Verified OK on 1st try."); ++ ++ java.security.cert.Certificate[] currentTrustedCerts; ++ BrowserCertsDialog bcd; ++ ++ SSLSession sess = socket.getSession(); ++ currentTrustedCerts = sess.getPeerCertificates(); ++ ++ if (viewer.trustAllVncCerts) { ++ dbg("viewer.trustAllVncCerts-1 keeping socket."); ++ } else if (currentTrustedCerts == null || currentTrustedCerts.length < 1) { ++ try { ++ socket.close(); ++ } catch (Exception e) { ++ dbg("socket is grumpy."); ++ } ++ socket = null; ++ throw new SSLHandshakeException("no current certs"); ++ } ++ ++ String serv = ""; ++ try { ++ CertInfo ci = new CertInfo(currentTrustedCerts[0]); ++ serv = ci.get_certinfo("CN"); ++ } catch (Exception e) { ++ ; ++ } ++ ++ if (viewer.trustAllVncCerts) { ++ dbg("viewer.trustAllVncCerts-2 skipping browser certs dialog"); ++ user_wants_to_see_cert = false; ++ } else if (viewer.serverCert != null && trustsrvCerts != null) { ++ dbg("viewer.serverCert-1 skipping browser certs dialog"); ++ user_wants_to_see_cert = false; ++ } else if (viewer.trustUrlVncCert) { ++ dbg("viewer.trustUrlVncCert-1 skipping browser certs dialog"); ++ user_wants_to_see_cert = false; ++ } else { ++ /* have a dialog with the user: */ ++ bcd = new BrowserCertsDialog(serv, host + ":" + port); ++ dbg("browser certs dialog begin."); ++ bcd.queryUser(); ++ dbg("browser certs dialog finished."); ++ ++ if (bcd.showCertDialog) { ++ String msg = "user wants to see cert"; ++ dbg(msg); ++ user_wants_to_see_cert = true; ++ if (cert_fail == null) { ++ cert_fail = "user-view"; ++ } ++ throw new SSLHandshakeException(msg); ++ } else { ++ user_wants_to_see_cert = false; ++ dbg("browser certs dialog: user said yes, accept it"); ++ } ++ } ++ ++ } catch (SSLHandshakeException eh) { ++ dbg("SSLHandshakeException: could not automatically verify Server."); ++ dbg("msg: " + eh.getMessage()); ++ ++ ++ /* send a cleanup string just in case: */ ++ String getoutstr = "GET /index.vnc HTTP/1.0\r\nConnection: close\r\n\r\n"; ++ ++ try { ++ OutputStream os = socket.getOutputStream(); ++ os.write(getoutstr.getBytes()); ++ socket.close(); ++ } catch (Exception e) { ++ dbg("socket is grumpy!"); ++ } ++ ++ /* reload */ ++ ++ socket = null; ++ ++ String reason = null; ++ ++ if (srv_cert) { ++ /* for serverCert usage we make this a fatal error. */ ++ throw new IOException("Fatal: VNC Server's Cert does not match Applet Parameter 'serverCert=...'"); ++ /* see below in TrustDialog were we describe this case to user anyway */ ++ } ++ ++ /* ++ * Reconnect, trusting any cert, so we can grab ++ * the cert to show it to the user in a dialog ++ * for him to manually accept. This connection ++ * is not used for anything else. ++ */ ++ factory = trustall_ctx.getSocketFactory(); ++ if (proxy_failure) { ++ socket = proxy_socket(factory); ++ } else { ++ socket = (SSLSocket) factory.createSocket(host, port); ++ } ++ ++ if (debug_certs) { ++ dbg("trusturlCerts: " + trusturlCerts); ++ dbg("trustsrvCerts: " + trustsrvCerts); ++ } ++ if (trusturlCerts == null && cert_fail == null) { ++ cert_fail = "missing-certs"; ++ } ++ ++ try { ++ socket.startHandshake(); ++ ++ dbg("The TrustAll Server Cert-grab Connection (trivially) Verified OK."); ++ ++ /* grab the cert: */ ++ try { ++ SSLSession sess = socket.getSession(); ++ trustallCerts = sess.getPeerCertificates(); ++ } catch (Exception e) { ++ throw new Exception("Could not get " + ++ "Peer Certificate"); ++ } ++ if (debug_certs) { ++ dbg("trustallCerts: " + trustallCerts); ++ } ++ ++ if (viewer.trustAllVncCerts) { ++ dbg("viewer.trustAllVncCerts-3. skipping dialog, trusting everything."); ++ } else if (! browser_cert_match()) { ++ /* ++ * close socket now, we will reopen after ++ * dialog if user agrees to use the cert. ++ */ ++ try { ++ OutputStream os = socket.getOutputStream(); ++ os.write(getoutstr.getBytes()); ++ socket.close(); ++ } catch (Exception e) { ++ dbg("socket is grumpy!!"); ++ } ++ socket = null; ++ ++ /* dialog with user to accept cert or not: */ ++ ++ TrustDialog td= new TrustDialog(host, port, ++ trustallCerts); ++ ++ if (cert_fail == null) { ++ ; ++ } else if (cert_fail.equals("user-view")) { ++ reason = "Reason for this Dialog:\n\n" ++ + " You Asked to View the Certificate."; ++ } else if (cert_fail.equals("server-cert-mismatch")) { ++ /* this is now fatal error, see above. */ ++ reason = "Reason for this Dialog:\n\n" ++ + " The VNC Server's Certificate does not match the Certificate\n" ++ + " specified in the supplied 'serverCert' Applet Parameter."; ++ } else if (cert_fail.equals("cert-mismatch")) { ++ reason = "Reason for this Dialog:\n\n" ++ + " The VNC Server's Certificate does not match the Website's\n" ++ + " HTTPS Certificate (that you previously accepted; either\n" ++ + " manually or automatically via Certificate Authority.)"; ++ } else if (cert_fail.equals("missing-certs")) { ++ reason = "Reason for this Dialog:\n\n" ++ + " Not all Certificates could be obtained to check."; ++ } ++ ++ if (! td.queryUser(reason)) { ++ String msg = "User decided against it."; ++ dbg(msg); ++ throw new IOException(msg); ++ } ++ } ++ ++ } catch (Exception ehand2) { ++ dbg("** Could not TrustAll Verify Server!"); ++ ++ throw new IOException(ehand2.getMessage()); ++ } ++ ++ /* reload again: */ ++ ++ if (socket != null) { ++ try { ++ socket.close(); ++ } catch (Exception e) { ++ dbg("socket is grumpy!!!"); ++ } ++ socket = null; ++ } ++ ++ /* ++ * Now connect a 3rd time, using the cert ++ * retrieved during connection 2 (sadly, that ++ * the user likely blindly agreed to...) ++ */ ++ ++ factory = trustone_ctx.getSocketFactory(); ++ if (proxy_failure) { ++ socket = proxy_socket(factory); ++ } else { ++ socket = (SSLSocket) factory.createSocket(host, port); ++ } ++ ++ try { ++ socket.startHandshake(); ++ dbg("TrustAll/TrustOne Server Connection Verified #3."); ++ ++ } catch (Exception ehand3) { ++ dbg("** Could not TrustAll/TrustOne Verify Server #3."); ++ ++ throw new IOException(ehand3.getMessage()); ++ } ++ } ++ ++ /* we have socket (possibly null) at this point, so proceed: */ ++ ++ /* handle x11vnc GET=1, if applicable: */ ++ if (socket != null && viewer.GET) { ++ String str = "GET "; ++ str += viewer.urlPrefix; ++ str += "/request.https.vnc.connection"; ++ str += " HTTP/1.0\r\n"; ++ str += "Pragma: No-Cache\r\n"; ++ str += "\r\n"; ++ ++ System.out.println("sending: " + str); ++ OutputStream os = socket.getOutputStream(); ++ String type = "os"; ++ ++ if (type == "os") { ++ os.write(str.getBytes()); ++ os.flush(); ++ System.out.println("used OutputStream"); ++ } else if (type == "bs") { ++ BufferedOutputStream bs = new BufferedOutputStream(os); ++ bs.write(str.getBytes()); ++ bs.flush(); ++ System.out.println("used BufferedOutputStream"); ++ } else if (type == "ds") { ++ DataOutputStream ds = new DataOutputStream(os); ++ ds.write(str.getBytes()); ++ ds.flush(); ++ System.out.println("used DataOutputStream"); ++ } ++ if (false) { ++ String rep = ""; ++ DataInputStream is = new DataInputStream( ++ new BufferedInputStream(socket.getInputStream(), 16384)); ++ while (true) { ++ rep += readline(is); ++ if (rep.indexOf("\r\n\r\n") >= 0) { ++ break; ++ } ++ } ++ System.out.println("rep: " + rep); ++ } ++ } ++ ++ dbg("SSL returning socket to caller."); ++ dbg(""); ++ ++ /* could be null, let caller handle that. */ ++ return (Socket) socket; ++ } ++ ++ boolean browser_cert_match() { ++ String msg = "Browser URL accept previously accepted cert"; ++ ++ if (user_wants_to_see_cert) { ++ return false; ++ } ++ ++ if (viewer.serverCert != null || trustsrvCerts != null) { ++ if (cert_fail == null) { ++ cert_fail = "server-cert-mismatch"; ++ } ++ } ++ if (trustallCerts != null && trusturlCerts != null) { ++ if (trustallCerts.length == trusturlCerts.length) { ++ boolean ok = true; ++ /* check toath trustallCerts (socket) equals trusturlCerts (browser) */ ++ for (int i = 0; i < trusturlCerts.length; i++) { ++ if (! trustallCerts[i].equals(trusturlCerts[i])) { ++ dbg("BCM: cert mismatch at i=" + i); ++ dbg("BCM: cert mismatch url" + trusturlCerts[i]); ++ dbg("BCM: cert mismatch all" + trustallCerts[i]); ++ ok = false; ++ } ++ } ++ if (ok) { ++ System.out.println(msg); ++ if (cert_fail == null) { ++ cert_fail = "did-not-fail"; ++ } ++ return true; ++ } else { ++ if (cert_fail == null) { ++ cert_fail = "cert-mismatch"; ++ } ++ return false; ++ } ++ } ++ } ++ if (cert_fail == null) { ++ cert_fail = "missing-certs"; ++ } ++ return false; ++ } ++ ++ private void dbg(String s) { ++ if (debug) { ++ System.out.println(s); ++ } ++ } ++ ++ private int gint(String s) { ++ int n = -1; ++ try { ++ Integer I = new Integer(s); ++ n = I.intValue(); ++ } catch (Exception ex) { ++ return -1; ++ } ++ return n; ++ } ++ ++ /* this will do the proxy CONNECT negotiation and hook us up. */ ++ ++ private void proxy_helper(String proxyHost, int proxyPort) { ++ ++ boolean proxy_auth = false; ++ String proxy_auth_basic_realm = ""; ++ String hp = host + ":" + port; ++ dbg("proxy_helper: " + proxyHost + ":" + proxyPort + " hp: " + hp); ++ ++ /* we loop here a few times trying for the password case */ ++ for (int k=0; k < 2; k++) { ++ dbg("proxy_in_use psocket: " + k); ++ ++ if (proxySock != null) { ++ try { ++ proxySock.close(); ++ } catch (Exception e) { ++ dbg("proxy socket is grumpy."); ++ } ++ } ++ ++ proxySock = psocket(proxyHost, proxyPort); ++ if (proxySock == null) { ++ dbg("1-a sadly, returning a null socket"); ++ return; ++ } ++ ++ String req1 = "CONNECT " + hp + " HTTP/1.1\r\n" ++ + "Host: " + hp + "\r\n"; ++ ++ dbg("requesting via proxy: " + req1); ++ ++ if (proxy_auth) { ++ if (proxy_auth_string == null) { ++ ProxyPasswdDialog pp = new ProxyPasswdDialog(proxyHost, proxyPort, proxy_auth_basic_realm); ++ pp.queryUser(); ++ proxy_auth_string = pp.getAuth(); ++ } ++ //dbg("auth1: " + proxy_auth_string); ++ ++ String auth2 = Base64Coder.encodeString(proxy_auth_string); ++ //dbg("auth2: " + auth2); ++ ++ req1 += "Proxy-Authorization: Basic " + auth2 + "\r\n"; ++ //dbg("req1: " + req1); ++ ++ dbg("added Proxy-Authorization: Basic ... to request"); ++ } ++ req1 += "\r\n"; ++ ++ try { ++ proxy_os.write(req1.getBytes()); ++ String reply = readline(proxy_is); ++ ++ dbg("proxy replied: " + reply.trim()); ++ ++ if (reply.indexOf("HTTP/1.") == 0 && reply.indexOf(" 407 ") > 0) { ++ proxy_auth = true; ++ proxySock.close(); ++ } else if (reply.indexOf("HTTP/1.") < 0 && reply.indexOf(" 200") < 0) { ++ proxySock.close(); ++ proxySock = psocket(proxyHost, proxyPort); ++ if (proxySock == null) { ++ dbg("2-a sadly, returning a null socket"); ++ return; ++ } ++ } ++ } catch(Exception e) { ++ dbg("some proxy socket problem: " + e.getMessage()); ++ } ++ ++ /* read the rest of the HTTP headers */ ++ while (true) { ++ String line = readline(proxy_is); ++ dbg("proxy line: " + line.trim()); ++ if (proxy_auth) { ++ String uc = line.toLowerCase(); ++ if (uc.indexOf("proxy-authenticate:") == 0) { ++ if (uc.indexOf(" basic ") >= 0) { ++ int idx = uc.indexOf(" realm"); ++ if (idx >= 0) { ++ proxy_auth_basic_realm = uc.substring(idx+1); ++ } ++ } ++ } ++ } ++ if (line.equals("\r\n") || line.equals("\n")) { ++ break; ++ } ++ } ++ if (!proxy_auth || proxy_auth_basic_realm.equals("")) { ++ /* we only try once for the non-password case: */ ++ break; ++ } ++ } ++ } ++ ++ public SSLSocket proxy_socket(SSLSocketFactory factory) { ++ Properties props = null; ++ String proxyHost = null; ++ int proxyPort = 0; ++ String proxyHost_nossl = null; ++ int proxyPort_nossl = 0; ++ String str; ++ ++ /* see if we can guess the proxy info from Properties: */ ++ try { ++ props = System.getProperties(); ++ } catch (Exception e) { ++ /* sandboxed applet might not be able to read it. */ ++ dbg("props failed: " + e.getMessage()); ++ } ++ if (viewer.proxyHost != null) { ++ dbg("Using supplied proxy " + viewer.proxyHost + " " + viewer.proxyPort + " applet parameters."); ++ proxyHost = viewer.proxyHost; ++ if (viewer.proxyPort != null) { ++ proxyPort = gint(viewer.proxyPort); ++ } else { ++ proxyPort = 8080; ++ } ++ ++ } else if (props != null) { ++ dbg("\n---------------\nAll props:"); ++ props.list(System.out); ++ dbg("\n---------------\n\n"); ++ ++ /* scrape throught properties looking for proxy info: */ ++ ++ for (Enumeration e = props.propertyNames(); e.hasMoreElements(); ) { ++ String s = (String) e.nextElement(); ++ String v = System.getProperty(s); ++ String s2 = s.toLowerCase(); ++ String v2 = v.toLowerCase(); ++ ++ if (s2.indexOf("proxy.https.host") >= 0) { ++ proxyHost = v2; ++ continue; ++ } ++ if (s2.indexOf("proxy.https.port") >= 0) { ++ proxyPort = gint(v2); ++ continue; ++ } ++ if (s2.indexOf("proxy.http.host") >= 0) { ++ proxyHost_nossl = v2; ++ continue; ++ } ++ if (s2.indexOf("proxy.http.port") >= 0) { ++ proxyPort_nossl = gint(v2); ++ continue; ++ } ++ } ++ ++ for (Enumeration e = props.propertyNames(); e.hasMoreElements(); ) { ++ String s = (String) e.nextElement(); ++ String v = System.getProperty(s); ++ String s2 = s.toLowerCase(); ++ String v2 = v.toLowerCase(); ++ ++ if (proxyHost != null && proxyPort > 0) { ++ break; ++ } ++ ++ // look for something like: javaplugin.proxy.config.list = http=10.0.2.1:8082 ++ if (s2.indexOf("proxy") < 0 && v2.indexOf("proxy") < 0) { ++ continue; ++ } ++ if (v2.indexOf("http") < 0) { ++ continue; ++ } ++ ++ String[] pieces = v.split("[,;]"); ++ for (int i = 0; i < pieces.length; i++) { ++ String p = pieces[i]; ++ int j = p.indexOf("https"); ++ if (j < 0) { ++ j = p.indexOf("http"); ++ if (j < 0) { ++ continue; ++ } ++ } ++ j = p.indexOf("=", j); ++ if (j < 0) { ++ continue; ++ } ++ p = p.substring(j+1); ++ String [] hp = p.split(":"); ++ if (hp.length != 2) { ++ continue; ++ } ++ if (hp[0].length() > 1 && hp[1].length() > 1) { ++ ++ proxyPort = gint(hp[1]); ++ if (proxyPort < 0) { ++ continue; ++ } ++ proxyHost = new String(hp[0]); ++ break; ++ } ++ } ++ } ++ } ++ if (proxyHost != null) { ++ if (proxyHost_nossl != null && proxyPort_nossl > 0) { ++ dbg("Using http proxy info instead of https."); ++ proxyHost = proxyHost_nossl; ++ proxyPort = proxyPort_nossl; ++ } ++ } ++ ++ if (proxy_in_use) { ++ if (proxy_dialog_host != null && proxy_dialog_port > 0) { ++ proxyHost = proxy_dialog_host; ++ proxyPort = proxy_dialog_port; ++ } ++ if (proxyHost != null) { ++ dbg("Lucky us! we figured out the Proxy parameters: " + proxyHost + " " + proxyPort); ++ } else { ++ /* ask user to help us: */ ++ ProxyDialog pd = new ProxyDialog(proxyHost, proxyPort); ++ pd.queryUser(); ++ proxyHost = pd.getHost(); ++ proxyPort = pd.getPort(); ++ proxy_dialog_host = new String(proxyHost); ++ proxy_dialog_port = proxyPort; ++ dbg("User said host: " + pd.getHost() + " port: " + pd.getPort()); ++ } ++ ++ proxy_helper(proxyHost, proxyPort); ++ if (proxySock == null) { ++ return null; ++ } ++ } else if (viewer.CONNECT != null) { ++ dbg("viewer.CONNECT psocket:"); ++ proxySock = psocket(host, port); ++ if (proxySock == null) { ++ dbg("1-b sadly, returning a null socket"); ++ return null; ++ } ++ } ++ ++ if (viewer.CONNECT != null) { ++ String hp = viewer.CONNECT; ++ String req2 = "CONNECT " + hp + " HTTP/1.1\r\n" ++ + "Host: " + hp + "\r\n\r\n"; ++ ++ dbg("requesting2: " + req2); ++ ++ try { ++ proxy_os.write(req2.getBytes()); ++ String reply = readline(proxy_is); ++ ++ dbg("proxy replied2: " + reply.trim()); ++ ++ if (reply.indexOf("HTTP/1.") < 0 && reply.indexOf(" 200") < 0) { ++ proxySock.close(); ++ proxySock = psocket(proxyHost, proxyPort); ++ if (proxySock == null) { ++ dbg("2-b sadly, returning a null socket"); ++ return null; ++ } ++ } ++ } catch(Exception e) { ++ dbg("proxy socket problem-2: " + e.getMessage()); ++ } ++ ++ while (true) { ++ String line = readline(proxy_is); ++ dbg("proxy line2: " + line.trim()); ++ if (line.equals("\r\n") || line.equals("\n")) { ++ break; ++ } ++ } ++ } ++ ++ Socket sslsock = null; ++ try { ++ sslsock = factory.createSocket(proxySock, host, port, true); ++ } catch(Exception e) { ++ dbg("sslsock prob: " + e.getMessage()); ++ dbg("3 sadly, returning a null socket"); ++ } ++ ++ return (SSLSocket) sslsock; ++ } ++ ++ Socket psocket(String h, int p) { ++ Socket psock = null; ++ try { ++ psock = new Socket(h, p); ++ proxy_is = new DataInputStream(new BufferedInputStream( ++ psock.getInputStream(), 16384)); ++ proxy_os = psock.getOutputStream(); ++ } catch(Exception e) { ++ dbg("psocket prob: " + e.getMessage()); ++ return null; ++ } ++ ++ return psock; ++ } ++ ++ String readline(DataInputStream i) { ++ byte[] ba = new byte[1]; ++ String s = new String(""); ++ ba[0] = 0; ++ try { ++ while (ba[0] != 0xa) { ++ ba[0] = (byte) i.readUnsignedByte(); ++ s += new String(ba); ++ } ++ } catch (Exception e) { ++ ; ++ } ++ return s; ++ } ++} ++ ++class TrustDialog implements ActionListener { ++ String msg, host, text; ++ int port; ++ java.security.cert.Certificate[] trustallCerts = null; ++ boolean viewing_cert = false; ++ boolean trust_this_session = false; ++ ++ /* ++ * this is the gui to show the user the cert and info and ask ++ * them if they want to continue using this cert. ++ */ ++ ++ Button ok, cancel, viewcert; ++ TextArea textarea; ++ Checkbox accept, deny; ++ Dialog dialog; ++ ++ String s1 = "Accept this certificate temporarily for this session"; ++ String s2 = "Do not accept this certificate and do not connect to" ++ + " this VNC server"; ++ String ln = "\n---------------------------------------------------\n\n"; ++ ++ TrustDialog (String h, int p, java.security.cert.Certificate[] s) { ++ host = h; ++ port = p; ++ trustallCerts = s; ++ ++ msg = "VNC Server " + host + ":" + port + " Not Verified"; ++ } ++ ++ public boolean queryUser(String reason) { ++ ++ /* create and display the dialog for unverified cert. */ ++ ++ Frame frame = new Frame(msg); ++ ++ dialog = new Dialog(frame, true); ++ ++ String infostr = ""; ++ if (trustallCerts.length == 1) { ++ CertInfo ci = new CertInfo(trustallCerts[0]); ++ infostr = ci.get_certinfo("all"); ++ } ++ if (reason != null) { ++ reason += "\n\n"; ++ } ++ ++ text = "\n" +++ "Unable to verify the identity of\n" +++ "\n" +++ " " + host + ":" + port + "\n" +++ "\n" +++ infostr +++ "\n" +++ "as a trusted VNC server.\n" +++ "\n" +++ reason +++ "In General not being able to verify the VNC Server and/or your seeing this Dialog\n" +++ "is due to one of the following:\n" +++ "\n" +++ " - Your requesting to View the Certificate before accepting.\n" +++ "\n" +++ " - The VNC server is using a Self-Signed Certificate or a Certificate\n" +++ " Authority not recognized by your Web Browser or Java Plugin runtime.\n" +++ "\n" +++ " - The use of an Apache SSL portal scheme employing CONNECT proxying AND\n" +++ " the Apache Web server has a certificate *different* from the VNC server's.\n" +++ "\n" +++ " - No previously accepted Certificate (via Web Broswer/Java Plugin) could be\n" +++ " obtained by this applet to compare the VNC Server Certificate against.\n" +++ "\n" +++ " - The VNC Server's Certificate does not match the one specified in the\n" +++ " supplied 'serverCert' Java Applet Parameter.\n" +++ "\n" +++ " - A Man-In-The-Middle attack impersonating as the VNC server that you wish\n" +++ " to connect to. (Wouldn't that be exciting!!)\n" +++ "\n" +++ "By safely copying the VNC server's Certificate (or using a common Certificate\n" +++ "Authority certificate) you can configure your Web Browser and Java Plugin to\n" +++ "automatically authenticate this VNC Server.\n" +++ "\n" +++ "If you do so, then you will only have to click \"Yes\" when this VNC Viewer\n" +++ "applet asks you whether to trust your Browser/Java Plugin's acceptance of the\n" +++ "certificate (except for the Apache portal case above where they don't match.)\n" +++ "\n" +++ "You can also set the applet parameter 'trustUrlVncCert=yes' to automatically\n" +++ "accept certificates already accepted/trusted by your Web Browser/Java Plugin,\n" +++ "and thereby see no dialog from this VNC Viewer applet.\n" ++; ++ ++ /* the accept / do-not-accept radio buttons: */ ++ CheckboxGroup checkbox = new CheckboxGroup(); ++ accept = new Checkbox(s1, true, checkbox); ++ deny = new Checkbox(s2, false, checkbox); ++ ++ /* put the checkboxes in a panel: */ ++ Panel check = new Panel(); ++ check.setLayout(new GridLayout(2, 1)); ++ ++ check.add(accept); ++ check.add(deny); ++ ++ /* make the 3 buttons: */ ++ ok = new Button("OK"); ++ cancel = new Button("Cancel"); ++ viewcert = new Button("View Certificate"); ++ ++ ok.addActionListener(this); ++ cancel.addActionListener(this); ++ viewcert.addActionListener(this); ++ ++ /* put the buttons in their own panel: */ ++ Panel buttonrow = new Panel(); ++ buttonrow.setLayout(new FlowLayout(FlowLayout.LEFT)); ++ buttonrow.add(viewcert); ++ buttonrow.add(ok); ++ buttonrow.add(cancel); ++ ++ /* label at the top: */ ++ Label label = new Label(msg, Label.CENTER); ++ label.setFont(new Font("Helvetica", Font.BOLD, 16)); ++ ++ /* textarea in the middle */ ++ textarea = new TextArea(text, 38, 64, ++ TextArea.SCROLLBARS_VERTICAL_ONLY); ++ textarea.setEditable(false); ++ ++ /* put the two panels in their own panel at bottom: */ ++ Panel bot = new Panel(); ++ bot.setLayout(new GridLayout(2, 1)); ++ bot.add(check); ++ bot.add(buttonrow); ++ ++ /* now arrange things inside the dialog: */ ++ dialog.setLayout(new BorderLayout()); ++ ++ dialog.add("North", label); ++ dialog.add("South", bot); ++ dialog.add("Center", textarea); ++ ++ dialog.pack(); ++ dialog.resize(dialog.preferredSize()); ++ ++ dialog.show(); /* block here til OK or Cancel pressed. */ ++ ++ return trust_this_session; ++ } ++ ++ public synchronized void actionPerformed(ActionEvent evt) { ++ ++ if (evt.getSource() == viewcert) { ++ /* View Certificate button clicked */ ++ if (viewing_cert) { ++ /* show the original info text: */ ++ textarea.setText(text); ++ viewcert.setLabel("View Certificate"); ++ viewing_cert = false; ++ } else { ++ int i; ++ /* show all (likely just one) certs: */ ++ textarea.setText(""); ++ for (i=0; i < trustallCerts.length; i++) { ++ int j = i + 1; ++ textarea.append("Certificate[" + ++ j + "]\n\n"); ++ textarea.append( ++ trustallCerts[i].toString()); ++ textarea.append(ln); ++ } ++ viewcert.setLabel("View Info"); ++ viewing_cert = true; ++ ++ textarea.setCaretPosition(0); ++ } ++ ++ } else if (evt.getSource() == ok) { ++ /* OK button clicked */ ++ if (accept.getState()) { ++ trust_this_session = true; ++ } else { ++ trust_this_session = false; ++ } ++ //dialog.dispose(); ++ dialog.hide(); ++ ++ } else if (evt.getSource() == cancel) { ++ /* Cancel button clicked */ ++ trust_this_session = false; ++ ++ //dialog.dispose(); ++ dialog.hide(); ++ } ++ } ++ ++ String get_certinfo() { ++ String all = ""; ++ String fields[] = {"CN", "OU", "O", "L", "C"}; ++ int i; ++ if (trustallCerts.length < 1) { ++ all = ""; ++ return all; ++ } ++ String cert = trustallCerts[0].toString(); ++ ++ /* ++ * For now we simply scrape the cert string, there must ++ * be an API for this... perhaps optionValue? ++ */ ++ ++ for (i=0; i < fields.length; i++) { ++ int f, t, t1, t2; ++ String sub, mat = fields[i] + "="; ++ ++ f = cert.indexOf(mat, 0); ++ if (f > 0) { ++ t1 = cert.indexOf(", ", f); ++ t2 = cert.indexOf("\n", f); ++ if (t1 < 0 && t2 < 0) { ++ continue; ++ } else if (t1 < 0) { ++ t = t2; ++ } else if (t2 < 0) { ++ t = t1; ++ } else if (t1 < t2) { ++ t = t1; ++ } else { ++ t = t2; ++ } ++ if (t > f) { ++ sub = cert.substring(f, t); ++ all = all + " " + sub + "\n"; ++ } ++ } ++ } ++ return all; ++ } ++} ++ ++class ProxyDialog implements ActionListener { ++ String guessedHost = null; ++ String guessedPort = null; ++ /* ++ * this is the gui to show the user the cert and info and ask ++ * them if they want to continue using this cert. ++ */ ++ ++ Button ok; ++ Dialog dialog; ++ TextField entry; ++ String reply = ""; ++ ++ ProxyDialog (String h, int p) { ++ guessedHost = h; ++ try { ++ guessedPort = Integer.toString(p); ++ } catch (Exception e) { ++ guessedPort = "8080"; ++ } ++ } ++ ++ public void queryUser() { ++ ++ /* create and display the dialog for unverified cert. */ ++ ++ Frame frame = new Frame("Need Proxy host:port"); ++ ++ dialog = new Dialog(frame, true); ++ ++ ++ Label label = new Label("Please Enter your https Proxy info as host:port", Label.CENTER); ++ //label.setFont(new Font("Helvetica", Font.BOLD, 16)); ++ entry = new TextField(30); ++ ok = new Button("OK"); ++ ok.addActionListener(this); ++ ++ String guess = ""; ++ if (guessedHost != null) { ++ guess = guessedHost + ":" + guessedPort; ++ } ++ entry.setText(guess); ++ ++ dialog.setLayout(new BorderLayout()); ++ dialog.add("North", label); ++ dialog.add("Center", entry); ++ dialog.add("South", ok); ++ dialog.pack(); ++ dialog.resize(dialog.preferredSize()); ++ ++ dialog.show(); /* block here til OK or Cancel pressed. */ ++ return; ++ } ++ ++ public String getHost() { ++ int i = reply.indexOf(":"); ++ if (i < 0) { ++ return "unknown"; ++ } ++ String h = reply.substring(0, i); ++ return h; ++ } ++ ++ public int getPort() { ++ int i = reply.indexOf(":"); ++ int p = 8080; ++ if (i < 0) { ++ return p; ++ } ++ i++; ++ String ps = reply.substring(i); ++ try { ++ Integer I = new Integer(ps); ++ p = I.intValue(); ++ } catch (Exception e) { ++ ; ++ } ++ return p; ++ } ++ ++ public synchronized void actionPerformed(ActionEvent evt) { ++ System.out.println(evt.getActionCommand()); ++ if (evt.getSource() == ok) { ++ reply = entry.getText(); ++ //dialog.dispose(); ++ dialog.hide(); ++ } ++ } ++} ++ ++class ProxyPasswdDialog implements ActionListener { ++ String guessedHost = null; ++ String guessedPort = null; ++ String guessedUser = null; ++ String guessedPasswd = null; ++ String realm = null; ++ /* ++ * this is the gui to show the user the cert and info and ask ++ * them if they want to continue using this cert. ++ */ ++ ++ Button ok; ++ Dialog dialog; ++ TextField entry1; ++ TextField entry2; ++ String reply1 = ""; ++ String reply2 = ""; ++ ++ ProxyPasswdDialog (String h, int p, String realm) { ++ guessedHost = h; ++ try { ++ guessedPort = Integer.toString(p); ++ } catch (Exception e) { ++ guessedPort = "8080"; ++ } ++ this.realm = realm; ++ } ++ ++ public void queryUser() { ++ ++ /* create and display the dialog for unverified cert. */ ++ ++ Frame frame = new Frame("Proxy Requires Username and Password"); ++ ++ dialog = new Dialog(frame, true); ++ ++ //Label label = new Label("Please Enter your Web Proxy Username in the top Entry and Password in the bottom Entry", Label.CENTER); ++ TextArea label = new TextArea("Please Enter your Web Proxy\nUsername in the Top Entry and\nPassword in the Bottom Entry,\nand then press OK.", 4, 20, TextArea.SCROLLBARS_NONE); ++ entry1 = new TextField(30); ++ entry2 = new TextField(30); ++ entry2.setEchoChar('*'); ++ ok = new Button("OK"); ++ ok.addActionListener(this); ++ ++ dialog.setLayout(new BorderLayout()); ++ dialog.add("North", label); ++ dialog.add("Center", entry1); ++ dialog.add("South", entry2); ++ dialog.add("East", ok); ++ dialog.pack(); ++ dialog.resize(dialog.preferredSize()); ++ ++ dialog.show(); /* block here til OK or Cancel pressed. */ ++ return; ++ } ++ ++ public String getAuth() { ++ return reply1 + ":" + reply2; ++ } ++ ++ public synchronized void actionPerformed(ActionEvent evt) { ++ System.out.println(evt.getActionCommand()); ++ if (evt.getSource() == ok) { ++ reply1 = entry1.getText(); ++ reply2 = entry2.getText(); ++ //dialog.dispose(); ++ dialog.hide(); ++ } ++ } ++} ++ ++class ClientCertDialog implements ActionListener { ++ ++ Button ok; ++ Dialog dialog; ++ TextField entry; ++ String reply = ""; ++ ++ ClientCertDialog() { ++ ; ++ } ++ ++ public String queryUser() { ++ ++ /* create and display the dialog for unverified cert. */ ++ ++ Frame frame = new Frame("Enter SSL Client Cert+Key String"); ++ ++ dialog = new Dialog(frame, true); ++ ++ ++ Label label = new Label("Please Enter the SSL Client Cert+Key String 308204c0...,...522d2d0a", Label.CENTER); ++ entry = new TextField(30); ++ ok = new Button("OK"); ++ ok.addActionListener(this); ++ ++ dialog.setLayout(new BorderLayout()); ++ dialog.add("North", label); ++ dialog.add("Center", entry); ++ dialog.add("South", ok); ++ dialog.pack(); ++ dialog.resize(dialog.preferredSize()); ++ ++ dialog.show(); /* block here til OK or Cancel pressed. */ ++ return reply; ++ } ++ ++ public synchronized void actionPerformed(ActionEvent evt) { ++ System.out.println(evt.getActionCommand()); ++ if (evt.getSource() == ok) { ++ reply = entry.getText(); ++ //dialog.dispose(); ++ dialog.hide(); ++ } ++ } ++} ++ ++class BrowserCertsDialog implements ActionListener { ++ Button yes, no; ++ Dialog dialog; ++ String vncServer; ++ String hostport; ++ public boolean showCertDialog = true; ++ ++ BrowserCertsDialog(String serv, String hp) { ++ vncServer = serv; ++ hostport = hp; ++ } ++ ++ public void queryUser() { ++ ++ /* create and display the dialog for unverified cert. */ ++ ++ Frame frame = new Frame("Use Browser/JVM Certs?"); ++ ++ dialog = new Dialog(frame, true); ++ ++ String m = ""; ++m += "\n"; ++m += "This VNC Viewer applet does not have its own keystore to track\n"; ++m += "SSL certificates, and so cannot authenticate the certificate\n"; ++m += "of the VNC Server:\n"; ++m += "\n"; ++m += " " + hostport + "\n\n " + vncServer + "\n"; ++m += "\n"; ++m += "on its own.\n"; ++m += "\n"; ++m += "However, it has noticed that your Web Browser and/or Java VM Plugin\n"; ++m += "has previously accepted the same certificate. You may have set\n"; ++m += "this up permanently or just for this session, or the server\n"; ++m += "certificate was signed by a CA cert that your Web Browser or\n"; ++m += "Java VM Plugin has.\n"; ++m += "\n"; ++m += "If the VNC Server connection times out while you are reading this\n"; ++m += "dialog, then restart the connection and try again.\n"; ++m += "\n"; ++m += "Should this VNC Viewer applet now connect to the above VNC server?\n"; ++m += "\n"; ++ ++ TextArea textarea = new TextArea(m, 22, 64, ++ TextArea.SCROLLBARS_VERTICAL_ONLY); ++ textarea.setEditable(false); ++ yes = new Button("Yes"); ++ yes.addActionListener(this); ++ no = new Button("No, Let Me See the Certificate."); ++ no.addActionListener(this); ++ ++ dialog.setLayout(new BorderLayout()); ++ dialog.add("North", textarea); ++ dialog.add("Center", yes); ++ dialog.add("South", no); ++ dialog.pack(); ++ dialog.resize(dialog.preferredSize()); ++ ++ dialog.show(); /* block here til Yes or No pressed. */ ++ System.out.println("done show()"); ++ return; ++ } ++ ++ public synchronized void actionPerformed(ActionEvent evt) { ++ System.out.println(evt.getActionCommand()); ++ if (evt.getSource() == yes) { ++ showCertDialog = false; ++ //dialog.dispose(); ++ dialog.hide(); ++ } else if (evt.getSource() == no) { ++ showCertDialog = true; ++ //dialog.dispose(); ++ dialog.hide(); ++ } ++ System.out.println("done actionPerformed()"); ++ } ++} ++ ++class CertInfo { ++ String fields[] = {"CN", "OU", "O", "L", "C"}; ++ java.security.cert.Certificate cert; ++ String certString = ""; ++ ++ CertInfo(java.security.cert.Certificate c) { ++ cert = c; ++ certString = cert.toString(); ++ } ++ ++ String get_certinfo(String which) { ++ int i; ++ String cs = new String(certString); ++ String all = ""; ++ ++ /* ++ * For now we simply scrape the cert string, there must ++ * be an API for this... perhaps optionValue? ++ */ ++ for (i=0; i < fields.length; i++) { ++ int f, t, t1, t2; ++ String sub, mat = fields[i] + "="; ++ ++ f = cs.indexOf(mat, 0); ++ if (f > 0) { ++ t1 = cs.indexOf(", ", f); ++ t2 = cs.indexOf("\n", f); ++ if (t1 < 0 && t2 < 0) { ++ continue; ++ } else if (t1 < 0) { ++ t = t2; ++ } else if (t2 < 0) { ++ t = t1; ++ } else if (t1 < t2) { ++ t = t1; ++ } else { ++ t = t2; ++ } ++ if (t > f) { ++ sub = cs.substring(f, t); ++ all = all + " " + sub + "\n"; ++ if (which.equals(fields[i])) { ++ return sub; ++ } ++ } ++ } ++ } ++ if (which.equals("all")) { ++ return all; ++ } else { ++ return ""; ++ } ++ } ++} ++ ++class Base64Coder { ++ ++ // Mapping table from 6-bit nibbles to Base64 characters. ++ private static char[] map1 = new char[64]; ++ static { ++ int i=0; ++ for (char c='A'; c<='Z'; c++) map1[i++] = c; ++ for (char c='a'; c<='z'; c++) map1[i++] = c; ++ for (char c='0'; c<='9'; c++) map1[i++] = c; ++ map1[i++] = '+'; map1[i++] = '/'; } ++ ++ // Mapping table from Base64 characters to 6-bit nibbles. ++ private static byte[] map2 = new byte[128]; ++ static { ++ for (int i=0; i<map2.length; i++) map2[i] = -1; ++ for (int i=0; i<64; i++) map2[map1[i]] = (byte)i; } ++ ++ /** ++ * Encodes a string into Base64 format. ++ * No blanks or line breaks are inserted. ++ * @param s a String to be encoded. ++ * @return A String with the Base64 encoded data. ++ */ ++ public static String encodeString (String s) { ++ return new String(encode(s.getBytes())); } ++ ++ /** ++ * Encodes a byte array into Base64 format. ++ * No blanks or line breaks are inserted. ++ * @param in an array containing the data bytes to be encoded. ++ * @return A character array with the Base64 encoded data. ++ */ ++ public static char[] encode (byte[] in) { ++ return encode(in,in.length); } ++ ++ /** ++ * Encodes a byte array into Base64 format. ++ * No blanks or line breaks are inserted. ++ * @param in an array containing the data bytes to be encoded. ++ * @param iLen number of bytes to process in <code>in</code>. ++ * @return A character array with the Base64 encoded data. ++ */ ++ public static char[] encode (byte[] in, int iLen) { ++ int oDataLen = (iLen*4+2)/3; // output length without padding ++ int oLen = ((iLen+2)/3)*4; // output length including padding ++ char[] out = new char[oLen]; ++ int ip = 0; ++ int op = 0; ++ while (ip < iLen) { ++ int i0 = in[ip++] & 0xff; ++ int i1 = ip < iLen ? in[ip++] & 0xff : 0; ++ int i2 = ip < iLen ? in[ip++] & 0xff : 0; ++ int o0 = i0 >>> 2; ++ int o1 = ((i0 & 3) << 4) | (i1 >>> 4); ++ int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6); ++ int o3 = i2 & 0x3F; ++ out[op++] = map1[o0]; ++ out[op++] = map1[o1]; ++ out[op] = op < oDataLen ? map1[o2] : '='; op++; ++ out[op] = op < oDataLen ? map1[o3] : '='; op++; } ++ return out; } ++ ++ /** ++ * Decodes a string from Base64 format. ++ * @param s a Base64 String to be decoded. ++ * @return A String containing the decoded data. ++ * @throws IllegalArgumentException if the input is not valid Base64 encoded data. ++ */ ++ public static String decodeString (String s) { ++ return new String(decode(s)); } ++ ++ /** ++ * Decodes a byte array from Base64 format. ++ * @param s a Base64 String to be decoded. ++ * @return An array containing the decoded data bytes. ++ * @throws IllegalArgumentException if the input is not valid Base64 encoded data. ++ */ ++ public static byte[] decode (String s) { ++ return decode(s.toCharArray()); } ++ ++ /** ++ * Decodes a byte array from Base64 format. ++ * No blanks or line breaks are allowed within the Base64 encoded data. ++ * @param in a character array containing the Base64 encoded data. ++ * @return An array containing the decoded data bytes. ++ * @throws IllegalArgumentException if the input is not valid Base64 encoded data. ++ */ ++ public static byte[] decode (char[] in) { ++ int iLen = in.length; ++ if (iLen%4 != 0) throw new IllegalArgumentException ("Length of Base64 encoded input string is not a multiple of 4."); ++ while (iLen > 0 && in[iLen-1] == '=') iLen--; ++ int oLen = (iLen*3) / 4; ++ byte[] out = new byte[oLen]; ++ int ip = 0; ++ int op = 0; ++ while (ip < iLen) { ++ int i0 = in[ip++]; ++ int i1 = in[ip++]; ++ int i2 = ip < iLen ? in[ip++] : 'A'; ++ int i3 = ip < iLen ? in[ip++] : 'A'; ++ if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127) ++ throw new IllegalArgumentException ("Illegal character in Base64 encoded data."); ++ int b0 = map2[i0]; ++ int b1 = map2[i1]; ++ int b2 = map2[i2]; ++ int b3 = map2[i3]; ++ if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0) ++ throw new IllegalArgumentException ("Illegal character in Base64 encoded data."); ++ int o0 = ( b0 <<2) | (b1>>>4); ++ int o1 = ((b1 & 0xf)<<4) | (b2>>>2); ++ int o2 = ((b2 & 3)<<6) | b3; ++ out[op++] = (byte)o0; ++ if (op<oLen) out[op++] = (byte)o1; ++ if (op<oLen) out[op++] = (byte)o2; } ++ return out; } ++ ++ // Dummy constructor. ++ private Base64Coder() {} ++ ++} +diff -Naur vnc_javasrc.orig/VncCanvas.java vnc_javasrc/VncCanvas.java +--- vnc_javasrc.orig/VncCanvas.java 2004-10-10 02:15:54.000000000 -0400 ++++ vnc_javasrc/VncCanvas.java 2010-11-30 21:01:15.000000000 -0500 +@@ -28,13 +28,14 @@ + import java.lang.*; + import java.util.zip.*; + ++import java.util.Collections; + + // + // VncCanvas is a subclass of Canvas which draws a VNC desktop on it. + // + + class VncCanvas extends Canvas +- implements KeyListener, MouseListener, MouseMotionListener { ++ implements KeyListener, MouseListener, MouseMotionListener, MouseWheelListener { + + VncViewer viewer; + RfbProto rfb; +@@ -81,6 +82,20 @@ + cm8 = new DirectColorModel(8, 7, (7 << 3), (3 << 6)); + cm24 = new DirectColorModel(24, 0xFF0000, 0x00FF00, 0x0000FF); + ++ // kludge to not show any Java cursor in the canvas since we are ++ // showing the soft cursor (should be a user setting...) ++ Cursor dot = Toolkit.getDefaultToolkit().createCustomCursor( ++ Toolkit.getDefaultToolkit().createImage(new byte[4]), new Point(0,0), ++ "dot"); ++ this.setCursor(dot); ++ ++ // while we are at it... get rid of the keyboard traversals that ++ // make it so we can't type a Tab character: ++ this.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, ++ Collections.EMPTY_SET); ++ this.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, ++ Collections.EMPTY_SET); ++ + colors = new Color[256]; + for (int i = 0; i < 256; i++) + colors[i] = new Color(cm8.getRGB(i)); +@@ -169,6 +184,7 @@ + inputEnabled = true; + addMouseListener(this); + addMouseMotionListener(this); ++ addMouseWheelListener(this); + if (viewer.showControls) { + viewer.buttonPanel.enableRemoteAccessControls(true); + } +@@ -177,6 +193,7 @@ + inputEnabled = false; + removeMouseListener(this); + removeMouseMotionListener(this); ++ removeMouseWheelListener(this); + if (viewer.showControls) { + viewer.buttonPanel.enableRemoteAccessControls(false); + } +@@ -1190,6 +1207,9 @@ + public void mouseDragged(MouseEvent evt) { + processLocalMouseEvent(evt, true); + } ++ public void mouseWheelMoved(MouseWheelEvent evt) { ++ processLocalMouseWheelEvent(evt); ++ } + + public void processLocalKeyEvent(KeyEvent evt) { + if (viewer.rfb != null && rfb.inNormalProtocol) { +@@ -1221,6 +1241,19 @@ + evt.consume(); + } + ++ public void processLocalMouseWheelEvent(MouseWheelEvent evt) { ++ if (viewer.rfb != null && rfb.inNormalProtocol) { ++ synchronized(rfb) { ++ try { ++ rfb.writeWheelEvent(evt); ++ } catch (Exception e) { ++ e.printStackTrace(); ++ } ++ rfb.notify(); ++ } ++ } ++ } ++ + public void processLocalMouseEvent(MouseEvent evt, boolean moved) { + if (viewer.rfb != null && rfb.inNormalProtocol) { + if (moved) { +@@ -1387,9 +1420,9 @@ + result = cm8.getRGB(pixBuf[i]); + } else { + result = 0xFF000000 | +- (pixBuf[i * 4 + 1] & 0xFF) << 16 | +- (pixBuf[i * 4 + 2] & 0xFF) << 8 | +- (pixBuf[i * 4 + 3] & 0xFF); ++ (pixBuf[i * 4 + 2] & 0xFF) << 16 | ++ (pixBuf[i * 4 + 1] & 0xFF) << 8 | ++ (pixBuf[i * 4 + 0] & 0xFF); + } + } else { + result = 0; // Transparent pixel +@@ -1403,9 +1436,9 @@ + result = cm8.getRGB(pixBuf[i]); + } else { + result = 0xFF000000 | +- (pixBuf[i * 4 + 1] & 0xFF) << 16 | +- (pixBuf[i * 4 + 2] & 0xFF) << 8 | +- (pixBuf[i * 4 + 3] & 0xFF); ++ (pixBuf[i * 4 + 2] & 0xFF) << 16 | ++ (pixBuf[i * 4 + 1] & 0xFF) << 8 | ++ (pixBuf[i * 4 + 0] & 0xFF); + } + } else { + result = 0; // Transparent pixel +diff -Naur vnc_javasrc.orig/VncViewer.java vnc_javasrc/VncViewer.java +--- vnc_javasrc.orig/VncViewer.java 2004-03-04 08:34:25.000000000 -0500 ++++ vnc_javasrc/VncViewer.java 2010-03-27 17:57:04.000000000 -0400 +@@ -29,6 +29,7 @@ + import java.awt.event.*; + import java.io.*; + import java.net.*; ++import java.util.*; + + public class VncViewer extends java.applet.Applet + implements java.lang.Runnable, WindowListener { +@@ -80,7 +81,7 @@ + // Variables read from parameter values. + String socketFactory; + String host; +- int port; ++ int port, vncserverport; + boolean showControls; + boolean offerRelogin; + boolean showOfflineDesktop; +@@ -88,6 +89,24 @@ + int deferCursorUpdates; + int deferUpdateRequests; + ++ boolean disableSSL; ++ boolean GET; ++ String CONNECT; ++ String urlPrefix; ++ String httpsPort; ++ String oneTimeKey; ++ String serverCert; ++ String proxyHost; ++ String proxyPort; ++ boolean forceProxy; ++ boolean ignoreProxy; ++ boolean trustAllVncCerts; ++ boolean trustUrlVncCert; ++ boolean debugCerts; ++ boolean debugKeyboard; ++ boolean mapF5_to_atsign; ++ boolean forbid_Ctrl_Alt; ++ + // Reference to this applet for inter-applet communication. + public static java.applet.Applet refApplet; + +@@ -282,10 +301,24 @@ + validate(); + } + +- while (!tryAuthenticate()) { +- authenticator.retry(); +- authenticatorUnixLogin.retry(); +- } ++ if (false) { ++ /* a bug on retries: 'Error: bad position: 8' sun.awt.X11.XTextFieldPeer.setCaretPosition(XTextFieldPeer.java:215) */ ++ while (!tryAuthenticate()) { ++ authenticator.retry(); ++ authenticatorUnixLogin.retry(); ++ } ++ } else { ++ /* just try once and not forever... */ ++ if (!tryAuthenticate()) { ++ showConnectionStatus("Authentication Failed."); ++ showMessage("Authentication Failed."); ++ if (!offerRelogin) { ++ fatalError("auth failed."); ++ } ++ } else { ++ //showConnectionStatus("Authentication OK."); ++ } ++ } + } + + +@@ -428,7 +461,10 @@ + gbc.ipadx = 100; + gbc.ipady = 50; + gridbag.setConstraints(authPanel, gbc); ++ try { + vncContainer.add(authPanel); ++ } catch (Exception e) { ++ } + + if (inSeparateFrame) { + vncFrame.pack(); +@@ -590,9 +626,28 @@ + fatalError("HOST parameter not specified"); + } + } ++ Date d = new Date(); ++ System.out.println("-\nSSL VNC Java Applet starting. " + d); + +- String str = readParameter("PORT", true); +- port = Integer.parseInt(str); ++ port = 0; ++ String str = readParameter("PORT", false); ++ if (str != null) { ++ port = Integer.parseInt(str); ++ } ++ // When there is a proxy VNCSERVERPORT may be inaccessible (inside firewall). ++ vncserverport = 0; ++ str = readParameter("VNCSERVERPORT", false); ++ if (str != null) { ++ vncserverport = Integer.parseInt(str); ++ } ++ if (port == 0 && vncserverport == 0) { ++ fatalError("Neither PORT nor VNCSERVERPORT parameters specified"); ++ } ++ if (port == 0) { ++ // Nevertheless, fall back to vncserverport if we have to. ++ System.out.println("using vncserverport: '" + vncserverport + "' for PORT."); ++ port = vncserverport; ++ } + + if (inAnApplet) { + str = readParameter("Open New Window", false); +@@ -626,6 +681,121 @@ + + // SocketFactory. + socketFactory = readParameter("SocketFactory", false); ++ ++ // SSL ++ disableSSL = false; ++ str = readParameter("DisableSSL", false); ++ if (str != null && str.equalsIgnoreCase("Yes")) ++ disableSSL = true; ++ ++ httpsPort = readParameter("httpsPort", false); ++ ++ // Extra GET, CONNECT string: ++ CONNECT = readParameter("CONNECT", false); ++ if (CONNECT != null) { ++ CONNECT = CONNECT.replaceAll(" ", ":"); ++ } ++ ++ GET = false; ++ str = readParameter("GET", false); ++ if (str != null && str.equalsIgnoreCase("Yes")) { ++ GET = true; ++ } ++ if (str != null && str.equalsIgnoreCase("1")) { ++ GET = true; ++ } ++ ++ urlPrefix = readParameter("urlPrefix", false); ++ if (urlPrefix != null) { ++ urlPrefix = urlPrefix.replaceAll("%2F", "/"); ++ urlPrefix = urlPrefix.replaceAll("%2f", "/"); ++ urlPrefix = urlPrefix.replaceAll("_2F_", "/"); ++ if (urlPrefix.indexOf("/") != 0) { ++ urlPrefix = "/" + urlPrefix; ++ } ++ } else { ++ urlPrefix = ""; ++ } ++ System.out.println("urlPrefix: '" + urlPrefix + "'"); ++ ++ oneTimeKey = readParameter("oneTimeKey", false); ++ if (oneTimeKey != null) { ++ System.out.println("oneTimeKey is set."); ++ } ++ ++ serverCert = readParameter("serverCert", false); ++ if (serverCert != null) { ++ System.out.println("serverCert is set."); ++ } ++ ++ forceProxy = false; ++ proxyHost = null; ++ proxyPort = null; ++ str = readParameter("forceProxy", false); ++ if (str != null) { ++ if (str.equalsIgnoreCase("Yes")) { ++ forceProxy = true; ++ } else if (str.equalsIgnoreCase("No")) { ++ forceProxy = false; ++ } else { ++ forceProxy = true; ++ String[] pieces = str.split(" "); ++ proxyHost = new String(pieces[0]); ++ if (pieces.length >= 2) { ++ proxyPort = new String(pieces[1]); ++ } else { ++ proxyPort = new String("8080"); ++ } ++ } ++ } ++ str = readParameter("proxyHost", false); ++ if (str != null) { ++ proxyHost = new String(str); ++ } ++ str = readParameter("proxyPort", false); ++ if (str != null) { ++ proxyPort = new String(str); ++ } ++ if (proxyHost != null && proxyPort == null) { ++ proxyPort = new String("8080"); ++ } ++ ++ ignoreProxy = false; ++ str = readParameter("ignoreProxy", false); ++ if (str != null && str.equalsIgnoreCase("Yes")) { ++ ignoreProxy = true; ++ } ++ ++ trustAllVncCerts = false; ++ str = readParameter("trustAllVncCerts", false); ++ if (str != null && str.equalsIgnoreCase("Yes")) { ++ trustAllVncCerts = true; ++ } ++ trustUrlVncCert = false; ++ str = readParameter("trustUrlVncCert", false); ++ if (str != null && str.equalsIgnoreCase("Yes")) { ++ trustUrlVncCert = true; ++ } ++ debugCerts = false; ++ str = readParameter("debugCerts", false); ++ if (str != null && str.equalsIgnoreCase("Yes")) { ++ debugCerts = true; ++ } ++ debugKeyboard = false; ++ str = readParameter("debugKeyboard", false); ++ if (str != null && str.equalsIgnoreCase("Yes")) { ++ debugKeyboard = true; ++ } ++ mapF5_to_atsign = false; ++ str = readParameter("mapF5_to_atsign", false); ++ if (str != null && str.equalsIgnoreCase("Yes")) { ++ mapF5_to_atsign = true; ++ } ++ forbid_Ctrl_Alt = false; ++ str = readParameter("forbid_Ctrl_Alt", false); ++ if (str != null && str.equalsIgnoreCase("Yes")) { ++ forbid_Ctrl_Alt = true; ++ } + } + + public String readParameter(String name, boolean required) { |