1diff -Naur vnc_javasrc.orig/Makefile vnc_javasrc/Makefile 2--- vnc_javasrc.orig/Makefile 2004-03-04 08:34:25.000000000 -0500 3+++ vnc_javasrc/Makefile 2010-05-18 20:56:26.000000000 -0400 4@@ -4,6 +4,7 @@ 5 6 CP = cp 7 JC = javac 8+JC_ARGS = -target 1.4 -source 1.4 9 JAR = jar 10 ARCHIVE = VncViewer.jar 11 MANIFEST = MANIFEST.MF 12@@ -15,25 +16,29 @@ 13 DesCipher.class CapabilityInfo.class CapsContainer.class \ 14 RecordingFrame.class SessionRecorder.class AuthUnixLoginPanel.class \ 15 SocketFactory.class HTTPConnectSocketFactory.class \ 16- HTTPConnectSocket.class ReloginPanel.class 17+ HTTPConnectSocket.class ReloginPanel.class \ 18+ SSLSocketToMe.class 19+ 20+SSL_CLASSES = SSLSocketToMe*.class TrustDialog.class 21 22 SOURCES = VncViewer.java RfbProto.java AuthPanel.java VncCanvas.java \ 23 OptionsFrame.java ClipboardFrame.java ButtonPanel.java \ 24 DesCipher.java CapabilityInfo.java CapsContainer.java \ 25 RecordingFrame.java SessionRecorder.java AuthUnixLoginPanel.java \ 26 SocketFactory.java HTTPConnectSocketFactory.java \ 27- HTTPConnectSocket.java ReloginPanel.java 28+ HTTPConnectSocket.java ReloginPanel.java \ 29+ SSLSocketToMe.java 30 31 all: $(CLASSES) $(ARCHIVE) 32 33 $(CLASSES): $(SOURCES) 34- $(JC) -target 1.1 -O $(SOURCES) 35+ $(JC) $(JC_ARGS) -O $(SOURCES) 36 37 $(ARCHIVE): $(CLASSES) $(MANIFEST) 38- $(JAR) cfm $(ARCHIVE) $(MANIFEST) $(CLASSES) 39+ $(JAR) cfm $(ARCHIVE) $(MANIFEST) $(CLASSES) $(SSL_CLASSES) 40 41 install: $(CLASSES) $(ARCHIVE) 42- $(CP) $(CLASSES) $(ARCHIVE) $(PAGES) $(INSTALL_DIR) 43+ $(CP) $(CLASSES) $(SSL_CLASSES) $(ARCHIVE) $(PAGES) $(INSTALL_DIR) 44 45 export:: $(CLASSES) $(ARCHIVE) $(PAGES) 46 @$(ExportJavaClasses) 47diff -Naur vnc_javasrc.orig/RfbProto.java vnc_javasrc/RfbProto.java 48--- vnc_javasrc.orig/RfbProto.java 2004-03-04 08:34:25.000000000 -0500 49+++ vnc_javasrc/RfbProto.java 2010-11-30 22:05:12.000000000 -0500 50@@ -199,7 +199,21 @@ 51 host = h; 52 port = p; 53 54- if (viewer.socketFactory == null) { 55+ if (! viewer.disableSSL) { 56+ System.out.println("new SSLSocketToMe"); 57+ SSLSocketToMe ssl; 58+ try { 59+ ssl = new SSLSocketToMe(host, port, v); 60+ } catch (Exception e) { 61+ throw new IOException(e.getMessage()); 62+ } 63+ 64+ try { 65+ sock = ssl.connectSock(); 66+ } catch (Exception es) { 67+ throw new IOException(es.getMessage()); 68+ } 69+ } else if (viewer.socketFactory == null) { 70 sock = new Socket(host, port); 71 } else { 72 try { 73@@ -255,7 +269,7 @@ 74 || (b[10] < '0') || (b[10] > '9') || (b[11] != '\n')) 75 { 76 throw new Exception("Host " + host + " port " + port + 77- " is not an RFB server"); 78+ " is not an RFB server: " + b); 79 } 80 81 serverMajor = (b[4] - '0') * 100 + (b[5] - '0') * 10 + (b[6] - '0'); 82@@ -892,6 +906,38 @@ 83 final static int ALT_MASK = InputEvent.ALT_MASK; 84 85 86+ void writeWheelEvent(MouseWheelEvent evt) throws IOException { 87+ 88+ eventBufLen = 0; 89+ 90+ int x = evt.getX(); 91+ int y = evt.getY(); 92+ 93+ if (x < 0) x = 0; 94+ if (y < 0) y = 0; 95+ 96+ int ptrmask; 97+ 98+ int clicks = evt.getWheelRotation(); 99+ System.out.println("writeWheelEvent: clicks: " + clicks); 100+ if (clicks > 0) { 101+ ptrmask = 16; 102+ } else if (clicks < 0) { 103+ ptrmask = 8; 104+ } else { 105+ return; 106+ } 107+ 108+ eventBuf[eventBufLen++] = (byte) PointerEvent; 109+ eventBuf[eventBufLen++] = (byte) ptrmask; 110+ eventBuf[eventBufLen++] = (byte) ((x >> 8) & 0xff); 111+ eventBuf[eventBufLen++] = (byte) (x & 0xff); 112+ eventBuf[eventBufLen++] = (byte) ((y >> 8) & 0xff); 113+ eventBuf[eventBufLen++] = (byte) (y & 0xff); 114+ 115+ os.write(eventBuf, 0, eventBufLen); 116+ } 117+ 118 // 119 // Write a pointer event message. We may need to send modifier key events 120 // around it to set the correct modifier state. 121@@ -992,6 +1038,19 @@ 122 boolean down = (evt.getID() == KeyEvent.KEY_PRESSED); 123 124 int key; 125+ if (viewer.debugKeyboard) { 126+ System.out.println("----------------------------------------"); 127+ System.out.println("evt.getKeyChar: " + evt.getKeyChar()); 128+ System.out.println("getKeyText: " + KeyEvent.getKeyText(evt.getKeyCode())); 129+ System.out.println("evt.getKeyCode: " + evt.getKeyCode()); 130+ System.out.println("evt.getID: " + evt.getID()); 131+ System.out.println("evt.getKeyLocation: " + evt.getKeyLocation()); 132+ System.out.println("evt.isActionKey: " + evt.isActionKey()); 133+ System.out.println("evt.isControlDown: " + evt.isControlDown()); 134+ System.out.println("evt.getModifiers: " + evt.getModifiers()); 135+ System.out.println("getKeyModifiersText: " + KeyEvent.getKeyModifiersText(evt.getModifiers())); 136+ System.out.println("evt.paramString: " + evt.paramString()); 137+ } 138 if (evt.isActionKey()) { 139 140 // 141@@ -1025,6 +1084,13 @@ 142 return; 143 } 144 145+ if(key == 0xffc2 && viewer.mapF5_to_atsign) { 146+ if (viewer.debugKeyboard) { 147+ System.out.println("Mapping: F5 -> AT "); 148+ } 149+ key = 0x40; 150+ } 151+ 152 } else { 153 154 // 155@@ -1036,6 +1102,7 @@ 156 157 key = keyChar; 158 159+ 160 if (key < 0x20) { 161 if (evt.isControlDown()) { 162 key += 0x60; 163@@ -1121,6 +1188,16 @@ 164 int oldModifiers = 0; 165 166 void writeModifierKeyEvents(int newModifiers) { 167+ if(viewer.forbid_Ctrl_Alt) { 168+ if ((newModifiers & CTRL_MASK) != 0 && (newModifiers & ALT_MASK) != 0) { 169+ int orig = newModifiers; 170+ newModifiers &= ~ALT_MASK; 171+ newModifiers &= ~CTRL_MASK; 172+ if (viewer.debugKeyboard) { 173+ System.out.println("Ctrl+Alt modifiers: " + orig + " -> " + newModifiers); 174+ } 175+ } 176+ } 177 if ((newModifiers & CTRL_MASK) != (oldModifiers & CTRL_MASK)) 178 writeKeyEvent(0xffe3, (newModifiers & CTRL_MASK) != 0); 179 180diff -Naur vnc_javasrc.orig/SSLSocketToMe.java vnc_javasrc/SSLSocketToMe.java 181--- vnc_javasrc.orig/SSLSocketToMe.java 1969-12-31 19:00:00.000000000 -0500 182+++ vnc_javasrc/SSLSocketToMe.java 2010-07-10 19:18:06.000000000 -0400 183@@ -0,0 +1,2067 @@ 184+/* 185+ * SSLSocketToMe.java: add SSL encryption to Java VNC Viewer. 186+ * 187+ * Copyright (c) 2006 Karl J. Runge <runge@karlrunge.com> 188+ * All rights reserved. 189+ * 190+ * This is free software; you can redistribute it and/or modify 191+ * it under the terms of the GNU General Public License as published by 192+ * the Free Software Foundation; version 2 of the License, or 193+ * (at your option) any later version. 194+ * 195+ * This software is distributed in the hope that it will be useful, 196+ * but WITHOUT ANY WARRANTY; without even the implied warranty of 197+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 198+ * GNU General Public License for more details. 199+ * 200+ * You should have received a copy of the GNU General Public License 201+ * along with this software; if not, write to the Free Software 202+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 203+ * USA. 204+ * 205+ */ 206+ 207+import java.net.*; 208+import java.io.*; 209+import javax.net.ssl.*; 210+import java.util.*; 211+ 212+import java.security.*; 213+import java.security.cert.*; 214+import java.security.spec.*; 215+import java.security.cert.Certificate; 216+import java.security.cert.CertificateFactory; 217+ 218+import java.awt.*; 219+import java.awt.event.*; 220+ 221+public class SSLSocketToMe { 222+ 223+ /* basic member data: */ 224+ String host; 225+ int port; 226+ VncViewer viewer; 227+ 228+ boolean debug = true; 229+ boolean debug_certs = false; 230+ 231+ /* sockets */ 232+ SSLSocket socket = null; 233+ SSLSocketFactory factory; 234+ 235+ /* fallback for Proxy connection */ 236+ boolean proxy_in_use = false; 237+ boolean proxy_failure = false; 238+ public DataInputStream is = null; 239+ public OutputStream os = null; 240+ 241+ /* strings from user WRT proxy: */ 242+ String proxy_auth_string = null; 243+ String proxy_dialog_host = null; 244+ int proxy_dialog_port = 0; 245+ 246+ Socket proxySock; 247+ DataInputStream proxy_is; 248+ OutputStream proxy_os; 249+ 250+ /* trust contexts */ 251+ SSLContext trustloc_ctx; 252+ SSLContext trustall_ctx; 253+ SSLContext trustsrv_ctx; 254+ SSLContext trusturl_ctx; 255+ SSLContext trustone_ctx; 256+ 257+ /* corresponding trust managers */ 258+ TrustManager[] trustAllCerts; 259+ TrustManager[] trustSrvCert; 260+ TrustManager[] trustUrlCert; 261+ TrustManager[] trustOneCert; 262+ 263+ /* client-side SSL auth key (oneTimeKey=...) */ 264+ KeyManager[] mykey = null; 265+ 266+ boolean user_wants_to_see_cert = true; 267+ String cert_fail = null; 268+ 269+ /* cert(s) we retrieve from Web server, VNC server, or serverCert param: */ 270+ java.security.cert.Certificate[] trustallCerts = null; 271+ java.security.cert.Certificate[] trustsrvCerts = null; 272+ java.security.cert.Certificate[] trusturlCerts = null; 273+ 274+ /* utility to decode hex oneTimeKey=... and serverCert=... */ 275+ byte[] hex2bytes(String s) { 276+ byte[] bytes = new byte[s.length()/2]; 277+ for (int i=0; i<s.length()/2; i++) { 278+ int j = 2*i; 279+ try { 280+ int val = Integer.parseInt(s.substring(j, j+2), 16); 281+ if (val > 127) { 282+ val -= 256; 283+ } 284+ Integer I = new Integer(val); 285+ bytes[i] = Byte.decode(I.toString()).byteValue(); 286+ 287+ } catch (Exception e) { 288+ ; 289+ } 290+ } 291+ return bytes; 292+ } 293+ 294+ SSLSocketToMe(String h, int p, VncViewer v) throws Exception { 295+ host = h; 296+ port = p; 297+ viewer = v; 298+ 299+ debug_certs = v.debugCerts; 300+ 301+ /* we will first try default factory for certification: */ 302+ 303+ factory = (SSLSocketFactory) SSLSocketFactory.getDefault(); 304+ 305+ dbg("SSL startup: " + host + " " + port); 306+ 307+ 308+ /* create trust managers to be used if initial handshake fails: */ 309+ 310+ trustAllCerts = new TrustManager[] { 311+ /* 312+ * this one accepts everything. Only used if user 313+ * has disabled checking (trustAllVncCerts=yes) 314+ * or when we grab the cert to show it to them in 315+ * a dialog and ask them to manually verify/accept it. 316+ */ 317+ new X509TrustManager() { 318+ public java.security.cert.X509Certificate[] 319+ getAcceptedIssuers() { 320+ return null; 321+ } 322+ public void checkClientTrusted( 323+ java.security.cert.X509Certificate[] certs, 324+ String authType) { 325+ /* empty */ 326+ } 327+ public void checkServerTrusted( 328+ java.security.cert.X509Certificate[] certs, 329+ String authType) { 330+ /* empty */ 331+ dbg("ALL: an untrusted connect to grab cert."); 332+ } 333+ } 334+ }; 335+ 336+ trustUrlCert = new TrustManager[] { 337+ /* 338+ * this one accepts only the retrieved server 339+ * cert by SSLSocket by this applet and stored in 340+ * trusturlCerts. 341+ */ 342+ new X509TrustManager() { 343+ public java.security.cert.X509Certificate[] 344+ getAcceptedIssuers() { 345+ return null; 346+ } 347+ public void checkClientTrusted( 348+ java.security.cert.X509Certificate[] certs, 349+ String authType) throws CertificateException { 350+ throw new CertificateException("No Clients (URL)"); 351+ } 352+ public void checkServerTrusted( 353+ java.security.cert.X509Certificate[] certs, 354+ String authType) throws CertificateException { 355+ /* we want to check 'certs' against 'trusturlCerts' */ 356+ if (trusturlCerts == null) { 357+ throw new CertificateException( 358+ "No Trust url Certs array."); 359+ } 360+ if (trusturlCerts.length < 1) { 361+ throw new CertificateException( 362+ "No Trust url Certs."); 363+ } 364+ if (certs == null) { 365+ throw new CertificateException( 366+ "No this-certs array."); 367+ } 368+ if (certs.length < 1) { 369+ throw new CertificateException( 370+ "No this-certs Certs."); 371+ } 372+ if (certs.length != trusturlCerts.length) { 373+ throw new CertificateException( 374+ "certs.length != trusturlCerts.length " + certs.length + " " + trusturlCerts.length); 375+ } 376+ boolean ok = true; 377+ for (int i = 0; i < certs.length; i++) { 378+ if (! trusturlCerts[i].equals(certs[i])) { 379+ ok = false; 380+ dbg("URL: cert mismatch at i=" + i); 381+ dbg("URL: cert mismatch cert" + certs[i]); 382+ dbg("URL: cert mismatch url" + trusturlCerts[i]); 383+ if (cert_fail == null) { 384+ cert_fail = "cert-mismatch"; 385+ } 386+ } 387+ if (debug_certs) { 388+ dbg("\n***********************************************"); 389+ dbg("URL: cert info at i=" + i); 390+ dbg("URL: cert info cert" + certs[i]); 391+ dbg("==============================================="); 392+ dbg("URL: cert info url" + trusturlCerts[i]); 393+ dbg("***********************************************"); 394+ } 395+ } 396+ if (!ok) { 397+ throw new CertificateException( 398+ "Server Cert Chain != URL Cert Chain."); 399+ } 400+ dbg("URL: trusturlCerts[i] matches certs[i] i=0:" + (certs.length-1)); 401+ } 402+ } 403+ }; 404+ 405+ trustSrvCert = new TrustManager[] { 406+ /* 407+ * this one accepts cert given to us in the serverCert 408+ * Applet Parameter we were started with. It is 409+ * currently a fatal error if the VNC Server's cert 410+ * doesn't match it. 411+ */ 412+ new X509TrustManager() { 413+ public java.security.cert.X509Certificate[] 414+ getAcceptedIssuers() { 415+ return null; 416+ } 417+ public void checkClientTrusted( 418+ java.security.cert.X509Certificate[] certs, 419+ String authType) throws CertificateException { 420+ throw new CertificateException("No Clients (SRV)"); 421+ } 422+ public void checkServerTrusted( 423+ java.security.cert.X509Certificate[] certs, 424+ String authType) throws CertificateException { 425+ /* we want to check 'certs' against 'trustsrvCerts' */ 426+ if (trustsrvCerts == null) { 427+ throw new CertificateException( 428+ "No Trust srv Certs array."); 429+ } 430+ if (trustsrvCerts.length < 1) { 431+ throw new CertificateException( 432+ "No Trust srv Certs."); 433+ } 434+ if (certs == null) { 435+ throw new CertificateException( 436+ "No this-certs array."); 437+ } 438+ if (certs.length < 1) { 439+ throw new CertificateException( 440+ "No this-certs Certs."); 441+ } 442+ if (certs.length != trustsrvCerts.length) { 443+ throw new CertificateException( 444+ "certs.length != trustsrvCerts.length " + certs.length + " " + trustsrvCerts.length); 445+ } 446+ boolean ok = true; 447+ for (int i = 0; i < certs.length; i++) { 448+ if (! trustsrvCerts[i].equals(certs[i])) { 449+ ok = false; 450+ dbg("SRV: cert mismatch at i=" + i); 451+ dbg("SRV: cert mismatch cert" + certs[i]); 452+ dbg("SRV: cert mismatch srv" + trustsrvCerts[i]); 453+ if (cert_fail == null) { 454+ cert_fail = "server-cert-mismatch"; 455+ } 456+ } 457+ if (debug_certs) { 458+ dbg("\n***********************************************"); 459+ dbg("SRV: cert info at i=" + i); 460+ dbg("SRV: cert info cert" + certs[i]); 461+ dbg("==============================================="); 462+ dbg("SRV: cert info srv" + trustsrvCerts[i]); 463+ dbg("***********************************************"); 464+ } 465+ } 466+ if (!ok) { 467+ throw new CertificateException( 468+ "Server Cert Chain != serverCert Applet Parameter Cert Chain."); 469+ } 470+ dbg("SRV: trustsrvCerts[i] matches certs[i] i=0:" + (certs.length-1)); 471+ } 472+ } 473+ }; 474+ 475+ trustOneCert = new TrustManager[] { 476+ /* 477+ * this one accepts only the retrieved server 478+ * cert by SSLSocket by this applet we stored in 479+ * trustallCerts that user has accepted or applet 480+ * parameter trustAllVncCerts=yes is set. This is 481+ * for when we reconnect after the user has manually 482+ * accepted the trustall cert in the dialog (or set 483+ * trustAllVncCerts=yes applet param.) 484+ */ 485+ new X509TrustManager() { 486+ public java.security.cert.X509Certificate[] 487+ getAcceptedIssuers() { 488+ return null; 489+ } 490+ public void checkClientTrusted( 491+ java.security.cert.X509Certificate[] certs, 492+ String authType) throws CertificateException { 493+ throw new CertificateException("No Clients (ONE)"); 494+ } 495+ public void checkServerTrusted( 496+ java.security.cert.X509Certificate[] certs, 497+ String authType) throws CertificateException { 498+ /* we want to check 'certs' against 'trustallCerts' */ 499+ if (trustallCerts == null) { 500+ throw new CertificateException( 501+ "No Trust All Server Certs array."); 502+ } 503+ if (trustallCerts.length < 1) { 504+ throw new CertificateException( 505+ "No Trust All Server Certs."); 506+ } 507+ if (certs == null) { 508+ throw new CertificateException( 509+ "No this-certs array."); 510+ } 511+ if (certs.length < 1) { 512+ throw new CertificateException( 513+ "No this-certs Certs."); 514+ } 515+ if (certs.length != trustallCerts.length) { 516+ throw new CertificateException( 517+ "certs.length != trustallCerts.length " + certs.length + " " + trustallCerts.length); 518+ } 519+ boolean ok = true; 520+ for (int i = 0; i < certs.length; i++) { 521+ if (! trustallCerts[i].equals(certs[i])) { 522+ ok = false; 523+ dbg("ONE: cert mismatch at i=" + i); 524+ dbg("ONE: cert mismatch cert" + certs[i]); 525+ dbg("ONE: cert mismatch all" + trustallCerts[i]); 526+ } 527+ if (debug_certs) { 528+ dbg("\n***********************************************"); 529+ dbg("ONE: cert info at i=" + i); 530+ dbg("ONE: cert info cert" + certs[i]); 531+ dbg("==============================================="); 532+ dbg("ONE: cert info all" + trustallCerts[i]); 533+ dbg("***********************************************"); 534+ } 535+ } 536+ if (!ok) { 537+ throw new CertificateException( 538+ "Server Cert Chain != TRUSTALL Cert Chain."); 539+ } 540+ dbg("ONE: trustallCerts[i] matches certs[i] i=0:" + (certs.length-1)); 541+ } 542+ } 543+ }; 544+ 545+ /* 546+ * The above TrustManagers are used: 547+ * 548+ * 1) to retrieve the server cert in case of failure to 549+ * display it to the user in a dialog. 550+ * 2) to subsequently connect to the server if user agrees. 551+ */ 552+ 553+ /* 554+ * build oneTimeKey cert+key if supplied in applet parameter: 555+ */ 556+ if (viewer.oneTimeKey != null && viewer.oneTimeKey.equals("PROMPT")) { 557+ ClientCertDialog d = new ClientCertDialog(); 558+ viewer.oneTimeKey = d.queryUser(); 559+ } 560+ if (viewer.oneTimeKey != null && viewer.oneTimeKey.indexOf(",") > 0) { 561+ int idx = viewer.oneTimeKey.indexOf(","); 562+ 563+ String onetimekey = viewer.oneTimeKey.substring(0, idx); 564+ byte[] key = hex2bytes(onetimekey); 565+ String onetimecert = viewer.oneTimeKey.substring(idx+1); 566+ byte[] cert = hex2bytes(onetimecert); 567+ 568+ KeyFactory kf = KeyFactory.getInstance("RSA"); 569+ PKCS8EncodedKeySpec keysp = new PKCS8EncodedKeySpec ( key ); 570+ PrivateKey ff = kf.generatePrivate (keysp); 571+ if (debug_certs) { 572+ dbg("one time key " + ff); 573+ } 574+ 575+ CertificateFactory cf = CertificateFactory.getInstance("X.509"); 576+ Collection c = cf.generateCertificates(new ByteArrayInputStream(cert)); 577+ Certificate[] certs = new Certificate[c.toArray().length]; 578+ if (c.size() == 1) { 579+ Certificate tmpcert = cf.generateCertificate(new ByteArrayInputStream(cert)); 580+ if (debug_certs) { 581+ dbg("one time cert" + tmpcert); 582+ } 583+ certs[0] = tmpcert; 584+ } else { 585+ certs = (Certificate[]) c.toArray(); 586+ } 587+ 588+ KeyStore ks = KeyStore.getInstance("JKS"); 589+ ks.load(null, null); 590+ ks.setKeyEntry("onetimekey", ff, "".toCharArray(), certs); 591+ String da = KeyManagerFactory.getDefaultAlgorithm(); 592+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(da); 593+ kmf.init(ks, "".toCharArray()); 594+ 595+ mykey = kmf.getKeyManagers(); 596+ } 597+ 598+ /* 599+ * build serverCert cert if supplied in applet parameter: 600+ */ 601+ if (viewer.serverCert != null) { 602+ CertificateFactory cf = CertificateFactory.getInstance("X.509"); 603+ byte[] cert = hex2bytes(viewer.serverCert); 604+ Collection c = cf.generateCertificates(new ByteArrayInputStream(cert)); 605+ trustsrvCerts = new Certificate[c.toArray().length]; 606+ if (c.size() == 1) { 607+ Certificate tmpcert = cf.generateCertificate(new ByteArrayInputStream(cert)); 608+ trustsrvCerts[0] = tmpcert; 609+ } else { 610+ trustsrvCerts = (Certificate[]) c.toArray(); 611+ } 612+ } 613+ 614+ /* the trust loc certs context: */ 615+ try { 616+ trustloc_ctx = SSLContext.getInstance("SSL"); 617+ 618+ /* 619+ * below is a failed attempt to get jvm's default 620+ * trust manager using null (below) makes it so 621+ * for HttpsURLConnection the server cannot be 622+ * verified (no prompting.) 623+ */ 624+ if (false) { 625+ boolean didit = false; 626+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 627+ tmf.init((KeyStore) null); 628+ TrustManager [] tml = tmf.getTrustManagers(); 629+ for (int i = 0; i < tml.length; i++) { 630+ TrustManager tm = tml[i]; 631+ if (tm instanceof X509TrustManager) { 632+ TrustManager tm1[] = new TrustManager[1]; 633+ tm1[0] = tm; 634+ trustloc_ctx.init(mykey, tm1, null); 635+ didit = true; 636+ break; 637+ } 638+ } 639+ if (!didit) { 640+ trustloc_ctx.init(mykey, null, null); 641+ } 642+ } else { 643+ /* we have to set trust manager to null */ 644+ trustloc_ctx.init(mykey, null, null); 645+ } 646+ 647+ } catch (Exception e) { 648+ String msg = "SSL trustloc_ctx FAILED."; 649+ dbg(msg); 650+ throw new Exception(msg); 651+ } 652+ 653+ /* the trust all certs context: */ 654+ try { 655+ trustall_ctx = SSLContext.getInstance("SSL"); 656+ trustall_ctx.init(mykey, trustAllCerts, new 657+ java.security.SecureRandom()); 658+ 659+ } catch (Exception e) { 660+ String msg = "SSL trustall_ctx FAILED."; 661+ dbg(msg); 662+ throw new Exception(msg); 663+ } 664+ 665+ /* the trust url certs context: */ 666+ try { 667+ trusturl_ctx = SSLContext.getInstance("SSL"); 668+ trusturl_ctx.init(mykey, trustUrlCert, new 669+ java.security.SecureRandom()); 670+ 671+ } catch (Exception e) { 672+ String msg = "SSL trusturl_ctx FAILED."; 673+ dbg(msg); 674+ throw new Exception(msg); 675+ } 676+ 677+ /* the trust srv certs context: */ 678+ try { 679+ trustsrv_ctx = SSLContext.getInstance("SSL"); 680+ trustsrv_ctx.init(mykey, trustSrvCert, new 681+ java.security.SecureRandom()); 682+ 683+ } catch (Exception e) { 684+ String msg = "SSL trustsrv_ctx FAILED."; 685+ dbg(msg); 686+ throw new Exception(msg); 687+ } 688+ 689+ /* the trust the one cert from server context: */ 690+ try { 691+ trustone_ctx = SSLContext.getInstance("SSL"); 692+ trustone_ctx.init(mykey, trustOneCert, new 693+ java.security.SecureRandom()); 694+ 695+ } catch (Exception e) { 696+ String msg = "SSL trustone_ctx FAILED."; 697+ dbg(msg); 698+ throw new Exception(msg); 699+ } 700+ } 701+ 702+ /* 703+ * we call this early on to 1) check for a proxy, 2) grab 704+ * Browser/JVM accepted HTTPS cert. 705+ */ 706+ public void check_for_proxy_and_grab_vnc_server_cert() { 707+ 708+ trusturlCerts = null; 709+ proxy_in_use = false; 710+ 711+ if (viewer.ignoreProxy) { 712+ /* applet param says skip it. */ 713+ /* the downside is we do not set trusturlCerts for comparison later... */ 714+ /* nor do we autodetect x11vnc for GET=1. */ 715+ return; 716+ } 717+ 718+ dbg("------------------------------------------------"); 719+ dbg("Into check_for_proxy_and_grab_vnc_server_cert():"); 720+ 721+ dbg("TRYING HTTPS:"); 722+ String ustr = "https://" + host + ":"; 723+ if (viewer.httpsPort != null) { 724+ ustr += viewer.httpsPort; 725+ } else { 726+ ustr += port; 727+ } 728+ ustr += viewer.urlPrefix + "/check.https.proxy.connection"; 729+ dbg("ustr is: " + ustr); 730+ 731+ try { 732+ /* prepare for an HTTPS URL connection to host:port */ 733+ URL url = new URL(ustr); 734+ HttpsURLConnection https = (HttpsURLConnection) url.openConnection(); 735+ 736+ if (mykey != null) { 737+ /* with oneTimeKey (mykey) we can't use the default SSL context */ 738+ if (trustsrvCerts != null) { 739+ dbg("passing trustsrv_ctx to HttpsURLConnection to provide client cert."); 740+ https.setSSLSocketFactory(trustsrv_ctx.getSocketFactory()); 741+ } else if (trustloc_ctx != null) { 742+ dbg("passing trustloc_ctx to HttpsURLConnection to provide client cert."); 743+ https.setSSLSocketFactory(trustloc_ctx.getSocketFactory()); 744+ } 745+ } 746+ 747+ https.setUseCaches(false); 748+ https.setRequestMethod("GET"); 749+ https.setRequestProperty("Pragma", "No-Cache"); 750+ https.setRequestProperty("Proxy-Connection", "Keep-Alive"); 751+ https.setDoInput(true); 752+ 753+ dbg("trying https.connect()"); 754+ https.connect(); 755+ 756+ dbg("trying https.getServerCertificates()"); 757+ trusturlCerts = https.getServerCertificates(); 758+ 759+ if (trusturlCerts == null) { 760+ dbg("set trusturlCerts to null!"); 761+ } else { 762+ dbg("set trusturlCerts to non-null"); 763+ } 764+ 765+ if (https.usingProxy()) { 766+ proxy_in_use = true; 767+ dbg("An HTTPS proxy is in use. There may be connection problems."); 768+ } 769+ 770+ dbg("trying https.getContent()"); 771+ Object output = https.getContent(); 772+ dbg("trying https.disconnect()"); 773+ https.disconnect(); 774+ if (! viewer.GET) { 775+ String header = https.getHeaderField("VNC-Server"); 776+ if (header != null && header.startsWith("x11vnc")) { 777+ dbg("detected x11vnc server (1), setting GET=1"); 778+ viewer.GET = true; 779+ } 780+ } 781+ 782+ } catch(Exception e) { 783+ dbg("HttpsURLConnection: " + e.getMessage()); 784+ } 785+ 786+ if (proxy_in_use) { 787+ dbg("exit check_for_proxy_and_grab_vnc_server_cert():"); 788+ dbg("------------------------------------------------"); 789+ return; 790+ } else if (trusturlCerts != null && !viewer.forceProxy) { 791+ /* Allow user to require HTTP check? use forceProxy for now. */ 792+ dbg("SKIPPING HTTP PROXY CHECK: got trusturlCerts, assuming proxy info is correct."); 793+ dbg("exit check_for_proxy_and_grab_vnc_server_cert():"); 794+ dbg("------------------------------------------------"); 795+ return; 796+ } 797+ 798+ /* 799+ * XXX need to remember scenario where this extra check 800+ * gives useful info. User's Browser proxy settings? 801+ */ 802+ dbg("TRYING HTTP:"); 803+ ustr = "http://" + host + ":" + port; 804+ ustr += viewer.urlPrefix + "/index.vnc"; 805+ dbg("ustr is: " + ustr); 806+ 807+ try { 808+ /* prepare for an HTTP URL connection to the same host:port (but not httpsPort) */ 809+ URL url = new URL(ustr); 810+ HttpURLConnection http = (HttpURLConnection) 811+ url.openConnection(); 812+ 813+ http.setUseCaches(false); 814+ http.setRequestMethod("GET"); 815+ http.setRequestProperty("Pragma", "No-Cache"); 816+ http.setRequestProperty("Proxy-Connection", "Keep-Alive"); 817+ http.setDoInput(true); 818+ 819+ dbg("trying http.connect()"); 820+ http.connect(); 821+ 822+ if (http.usingProxy()) { 823+ proxy_in_use = true; 824+ dbg("An HTTP proxy is in use. There may be connection problems."); 825+ } 826+ dbg("trying http.getContent()"); 827+ Object output = http.getContent(); 828+ dbg("trying http.disconnect()"); 829+ http.disconnect(); 830+ if (! viewer.GET) { 831+ String header = http.getHeaderField("VNC-Server"); 832+ if (header != null && header.startsWith("x11vnc")) { 833+ dbg("detected x11vnc server (2), setting GET=1"); 834+ viewer.GET = true; 835+ } 836+ } 837+ } catch(Exception e) { 838+ dbg("HttpURLConnection: " + e.getMessage()); 839+ } 840+ dbg("exit check_for_proxy_and_grab_vnc_server_cert():"); 841+ dbg("------------------------------------------------"); 842+ } 843+ 844+ public Socket connectSock() throws IOException { 845+ /* 846+ * first try a https connection to detect a proxy, and 847+ * grab the VNC server cert at the same time: 848+ */ 849+ check_for_proxy_and_grab_vnc_server_cert(); 850+ 851+ boolean srv_cert = false; 852+ 853+ if (trustsrvCerts != null) { 854+ /* applet parameter suppled serverCert */ 855+ dbg("viewer.trustSrvCert-0 using trustsrv_ctx"); 856+ factory = trustsrv_ctx.getSocketFactory(); 857+ srv_cert = true; 858+ } else if (viewer.trustAllVncCerts) { 859+ /* trust all certs (no checking) */ 860+ dbg("viewer.trustAllVncCerts-0 using trustall_ctx"); 861+ factory = trustall_ctx.getSocketFactory(); 862+ } else if (trusturlCerts != null) { 863+ /* trust certs the Browser/JVM accepted in check_for_proxy... */ 864+ dbg("using trusturl_ctx"); 865+ factory = trusturl_ctx.getSocketFactory(); 866+ } else { 867+ /* trust the local defaults */ 868+ dbg("using trustloc_ctx"); 869+ factory = trustloc_ctx.getSocketFactory(); 870+ } 871+ 872+ socket = null; 873+ 874+ try { 875+ if (proxy_in_use && viewer.forceProxy) { 876+ throw new Exception("forcing proxy (forceProxy)"); 877+ } else if (viewer.CONNECT != null) { 878+ throw new Exception("forcing CONNECT"); 879+ } 880+ 881+ int timeout = 6; 882+ if (timeout > 0) { 883+ socket = (SSLSocket) factory.createSocket(); 884+ InetSocketAddress inetaddr = new InetSocketAddress(host, port); 885+ dbg("Using timeout of " + timeout + " secs to: " + host + ":" + port); 886+ socket.connect(inetaddr, timeout * 1000); 887+ } else { 888+ socket = (SSLSocket) factory.createSocket(host, port); 889+ } 890+ 891+ } catch (Exception esock) { 892+ dbg("socket error: " + esock.getMessage()); 893+ if (proxy_in_use || viewer.CONNECT != null) { 894+ proxy_failure = true; 895+ if (proxy_in_use) { 896+ dbg("HTTPS proxy in use. Trying to go with it."); 897+ } else { 898+ dbg("viewer.CONNECT reverse proxy in use. Trying to go with it."); 899+ } 900+ try { 901+ socket = proxy_socket(factory); 902+ } catch (Exception e) { 903+ dbg("proxy_socket error: " + e.getMessage()); 904+ } 905+ } else { 906+ /* n.b. socket is left in error state to cause ex. below. */ 907+ } 908+ } 909+ 910+ try { 911+ socket.startHandshake(); 912+ 913+ dbg("The Server Connection Verified OK on 1st try."); 914+ 915+ java.security.cert.Certificate[] currentTrustedCerts; 916+ BrowserCertsDialog bcd; 917+ 918+ SSLSession sess = socket.getSession(); 919+ currentTrustedCerts = sess.getPeerCertificates(); 920+ 921+ if (viewer.trustAllVncCerts) { 922+ dbg("viewer.trustAllVncCerts-1 keeping socket."); 923+ } else if (currentTrustedCerts == null || currentTrustedCerts.length < 1) { 924+ try { 925+ socket.close(); 926+ } catch (Exception e) { 927+ dbg("socket is grumpy."); 928+ } 929+ socket = null; 930+ throw new SSLHandshakeException("no current certs"); 931+ } 932+ 933+ String serv = ""; 934+ try { 935+ CertInfo ci = new CertInfo(currentTrustedCerts[0]); 936+ serv = ci.get_certinfo("CN"); 937+ } catch (Exception e) { 938+ ; 939+ } 940+ 941+ if (viewer.trustAllVncCerts) { 942+ dbg("viewer.trustAllVncCerts-2 skipping browser certs dialog"); 943+ user_wants_to_see_cert = false; 944+ } else if (viewer.serverCert != null && trustsrvCerts != null) { 945+ dbg("viewer.serverCert-1 skipping browser certs dialog"); 946+ user_wants_to_see_cert = false; 947+ } else if (viewer.trustUrlVncCert) { 948+ dbg("viewer.trustUrlVncCert-1 skipping browser certs dialog"); 949+ user_wants_to_see_cert = false; 950+ } else { 951+ /* have a dialog with the user: */ 952+ bcd = new BrowserCertsDialog(serv, host + ":" + port); 953+ dbg("browser certs dialog begin."); 954+ bcd.queryUser(); 955+ dbg("browser certs dialog finished."); 956+ 957+ if (bcd.showCertDialog) { 958+ String msg = "user wants to see cert"; 959+ dbg(msg); 960+ user_wants_to_see_cert = true; 961+ if (cert_fail == null) { 962+ cert_fail = "user-view"; 963+ } 964+ throw new SSLHandshakeException(msg); 965+ } else { 966+ user_wants_to_see_cert = false; 967+ dbg("browser certs dialog: user said yes, accept it"); 968+ } 969+ } 970+ 971+ } catch (SSLHandshakeException eh) { 972+ dbg("SSLHandshakeException: could not automatically verify Server."); 973+ dbg("msg: " + eh.getMessage()); 974+ 975+ 976+ /* send a cleanup string just in case: */ 977+ String getoutstr = "GET /index.vnc HTTP/1.0\r\nConnection: close\r\n\r\n"; 978+ 979+ try { 980+ OutputStream os = socket.getOutputStream(); 981+ os.write(getoutstr.getBytes()); 982+ socket.close(); 983+ } catch (Exception e) { 984+ dbg("socket is grumpy!"); 985+ } 986+ 987+ /* reload */ 988+ 989+ socket = null; 990+ 991+ String reason = null; 992+ 993+ if (srv_cert) { 994+ /* for serverCert usage we make this a fatal error. */ 995+ throw new IOException("Fatal: VNC Server's Cert does not match Applet Parameter 'serverCert=...'"); 996+ /* see below in TrustDialog were we describe this case to user anyway */ 997+ } 998+ 999+ /* 1000+ * Reconnect, trusting any cert, so we can grab 1001+ * the cert to show it to the user in a dialog 1002+ * for him to manually accept. This connection 1003+ * is not used for anything else. 1004+ */ 1005+ factory = trustall_ctx.getSocketFactory(); 1006+ if (proxy_failure) { 1007+ socket = proxy_socket(factory); 1008+ } else { 1009+ socket = (SSLSocket) factory.createSocket(host, port); 1010+ } 1011+ 1012+ if (debug_certs) { 1013+ dbg("trusturlCerts: " + trusturlCerts); 1014+ dbg("trustsrvCerts: " + trustsrvCerts); 1015+ } 1016+ if (trusturlCerts == null && cert_fail == null) { 1017+ cert_fail = "missing-certs"; 1018+ } 1019+ 1020+ try { 1021+ socket.startHandshake(); 1022+ 1023+ dbg("The TrustAll Server Cert-grab Connection (trivially) Verified OK."); 1024+ 1025+ /* grab the cert: */ 1026+ try { 1027+ SSLSession sess = socket.getSession(); 1028+ trustallCerts = sess.getPeerCertificates(); 1029+ } catch (Exception e) { 1030+ throw new Exception("Could not get " + 1031+ "Peer Certificate"); 1032+ } 1033+ if (debug_certs) { 1034+ dbg("trustallCerts: " + trustallCerts); 1035+ } 1036+ 1037+ if (viewer.trustAllVncCerts) { 1038+ dbg("viewer.trustAllVncCerts-3. skipping dialog, trusting everything."); 1039+ } else if (! browser_cert_match()) { 1040+ /* 1041+ * close socket now, we will reopen after 1042+ * dialog if user agrees to use the cert. 1043+ */ 1044+ try { 1045+ OutputStream os = socket.getOutputStream(); 1046+ os.write(getoutstr.getBytes()); 1047+ socket.close(); 1048+ } catch (Exception e) { 1049+ dbg("socket is grumpy!!"); 1050+ } 1051+ socket = null; 1052+ 1053+ /* dialog with user to accept cert or not: */ 1054+ 1055+ TrustDialog td= new TrustDialog(host, port, 1056+ trustallCerts); 1057+ 1058+ if (cert_fail == null) { 1059+ ; 1060+ } else if (cert_fail.equals("user-view")) { 1061+ reason = "Reason for this Dialog:\n\n" 1062+ + " You Asked to View the Certificate."; 1063+ } else if (cert_fail.equals("server-cert-mismatch")) { 1064+ /* this is now fatal error, see above. */ 1065+ reason = "Reason for this Dialog:\n\n" 1066+ + " The VNC Server's Certificate does not match the Certificate\n" 1067+ + " specified in the supplied 'serverCert' Applet Parameter."; 1068+ } else if (cert_fail.equals("cert-mismatch")) { 1069+ reason = "Reason for this Dialog:\n\n" 1070+ + " The VNC Server's Certificate does not match the Website's\n" 1071+ + " HTTPS Certificate (that you previously accepted; either\n" 1072+ + " manually or automatically via Certificate Authority.)"; 1073+ } else if (cert_fail.equals("missing-certs")) { 1074+ reason = "Reason for this Dialog:\n\n" 1075+ + " Not all Certificates could be obtained to check."; 1076+ } 1077+ 1078+ if (! td.queryUser(reason)) { 1079+ String msg = "User decided against it."; 1080+ dbg(msg); 1081+ throw new IOException(msg); 1082+ } 1083+ } 1084+ 1085+ } catch (Exception ehand2) { 1086+ dbg("** Could not TrustAll Verify Server!"); 1087+ 1088+ throw new IOException(ehand2.getMessage()); 1089+ } 1090+ 1091+ /* reload again: */ 1092+ 1093+ if (socket != null) { 1094+ try { 1095+ socket.close(); 1096+ } catch (Exception e) { 1097+ dbg("socket is grumpy!!!"); 1098+ } 1099+ socket = null; 1100+ } 1101+ 1102+ /* 1103+ * Now connect a 3rd time, using the cert 1104+ * retrieved during connection 2 (sadly, that 1105+ * the user likely blindly agreed to...) 1106+ */ 1107+ 1108+ factory = trustone_ctx.getSocketFactory(); 1109+ if (proxy_failure) { 1110+ socket = proxy_socket(factory); 1111+ } else { 1112+ socket = (SSLSocket) factory.createSocket(host, port); 1113+ } 1114+ 1115+ try { 1116+ socket.startHandshake(); 1117+ dbg("TrustAll/TrustOne Server Connection Verified #3."); 1118+ 1119+ } catch (Exception ehand3) { 1120+ dbg("** Could not TrustAll/TrustOne Verify Server #3."); 1121+ 1122+ throw new IOException(ehand3.getMessage()); 1123+ } 1124+ } 1125+ 1126+ /* we have socket (possibly null) at this point, so proceed: */ 1127+ 1128+ /* handle x11vnc GET=1, if applicable: */ 1129+ if (socket != null && viewer.GET) { 1130+ String str = "GET "; 1131+ str += viewer.urlPrefix; 1132+ str += "/request.https.vnc.connection"; 1133+ str += " HTTP/1.0\r\n"; 1134+ str += "Pragma: No-Cache\r\n"; 1135+ str += "\r\n"; 1136+ 1137+ System.out.println("sending: " + str); 1138+ OutputStream os = socket.getOutputStream(); 1139+ String type = "os"; 1140+ 1141+ if (type == "os") { 1142+ os.write(str.getBytes()); 1143+ os.flush(); 1144+ System.out.println("used OutputStream"); 1145+ } else if (type == "bs") { 1146+ BufferedOutputStream bs = new BufferedOutputStream(os); 1147+ bs.write(str.getBytes()); 1148+ bs.flush(); 1149+ System.out.println("used BufferedOutputStream"); 1150+ } else if (type == "ds") { 1151+ DataOutputStream ds = new DataOutputStream(os); 1152+ ds.write(str.getBytes()); 1153+ ds.flush(); 1154+ System.out.println("used DataOutputStream"); 1155+ } 1156+ if (false) { 1157+ String rep = ""; 1158+ DataInputStream is = new DataInputStream( 1159+ new BufferedInputStream(socket.getInputStream(), 16384)); 1160+ while (true) { 1161+ rep += readline(is); 1162+ if (rep.indexOf("\r\n\r\n") >= 0) { 1163+ break; 1164+ } 1165+ } 1166+ System.out.println("rep: " + rep); 1167+ } 1168+ } 1169+ 1170+ dbg("SSL returning socket to caller."); 1171+ dbg(""); 1172+ 1173+ /* could be null, let caller handle that. */ 1174+ return (Socket) socket; 1175+ } 1176+ 1177+ boolean browser_cert_match() { 1178+ String msg = "Browser URL accept previously accepted cert"; 1179+ 1180+ if (user_wants_to_see_cert) { 1181+ return false; 1182+ } 1183+ 1184+ if (viewer.serverCert != null || trustsrvCerts != null) { 1185+ if (cert_fail == null) { 1186+ cert_fail = "server-cert-mismatch"; 1187+ } 1188+ } 1189+ if (trustallCerts != null && trusturlCerts != null) { 1190+ if (trustallCerts.length == trusturlCerts.length) { 1191+ boolean ok = true; 1192+ /* check toath trustallCerts (socket) equals trusturlCerts (browser) */ 1193+ for (int i = 0; i < trusturlCerts.length; i++) { 1194+ if (! trustallCerts[i].equals(trusturlCerts[i])) { 1195+ dbg("BCM: cert mismatch at i=" + i); 1196+ dbg("BCM: cert mismatch url" + trusturlCerts[i]); 1197+ dbg("BCM: cert mismatch all" + trustallCerts[i]); 1198+ ok = false; 1199+ } 1200+ } 1201+ if (ok) { 1202+ System.out.println(msg); 1203+ if (cert_fail == null) { 1204+ cert_fail = "did-not-fail"; 1205+ } 1206+ return true; 1207+ } else { 1208+ if (cert_fail == null) { 1209+ cert_fail = "cert-mismatch"; 1210+ } 1211+ return false; 1212+ } 1213+ } 1214+ } 1215+ if (cert_fail == null) { 1216+ cert_fail = "missing-certs"; 1217+ } 1218+ return false; 1219+ } 1220+ 1221+ private void dbg(String s) { 1222+ if (debug) { 1223+ System.out.println(s); 1224+ } 1225+ } 1226+ 1227+ private int gint(String s) { 1228+ int n = -1; 1229+ try { 1230+ Integer I = new Integer(s); 1231+ n = I.intValue(); 1232+ } catch (Exception ex) { 1233+ return -1; 1234+ } 1235+ return n; 1236+ } 1237+ 1238+ /* this will do the proxy CONNECT negotiation and hook us up. */ 1239+ 1240+ private void proxy_helper(String proxyHost, int proxyPort) { 1241+ 1242+ boolean proxy_auth = false; 1243+ String proxy_auth_basic_realm = ""; 1244+ String hp = host + ":" + port; 1245+ dbg("proxy_helper: " + proxyHost + ":" + proxyPort + " hp: " + hp); 1246+ 1247+ /* we loop here a few times trying for the password case */ 1248+ for (int k=0; k < 2; k++) { 1249+ dbg("proxy_in_use psocket: " + k); 1250+ 1251+ if (proxySock != null) { 1252+ try { 1253+ proxySock.close(); 1254+ } catch (Exception e) { 1255+ dbg("proxy socket is grumpy."); 1256+ } 1257+ } 1258+ 1259+ proxySock = psocket(proxyHost, proxyPort); 1260+ if (proxySock == null) { 1261+ dbg("1-a sadly, returning a null socket"); 1262+ return; 1263+ } 1264+ 1265+ String req1 = "CONNECT " + hp + " HTTP/1.1\r\n" 1266+ + "Host: " + hp + "\r\n"; 1267+ 1268+ dbg("requesting via proxy: " + req1); 1269+ 1270+ if (proxy_auth) { 1271+ if (proxy_auth_string == null) { 1272+ ProxyPasswdDialog pp = new ProxyPasswdDialog(proxyHost, proxyPort, proxy_auth_basic_realm); 1273+ pp.queryUser(); 1274+ proxy_auth_string = pp.getAuth(); 1275+ } 1276+ //dbg("auth1: " + proxy_auth_string); 1277+ 1278+ String auth2 = Base64Coder.encodeString(proxy_auth_string); 1279+ //dbg("auth2: " + auth2); 1280+ 1281+ req1 += "Proxy-Authorization: Basic " + auth2 + "\r\n"; 1282+ //dbg("req1: " + req1); 1283+ 1284+ dbg("added Proxy-Authorization: Basic ... to request"); 1285+ } 1286+ req1 += "\r\n"; 1287+ 1288+ try { 1289+ proxy_os.write(req1.getBytes()); 1290+ String reply = readline(proxy_is); 1291+ 1292+ dbg("proxy replied: " + reply.trim()); 1293+ 1294+ if (reply.indexOf("HTTP/1.") == 0 && reply.indexOf(" 407 ") > 0) { 1295+ proxy_auth = true; 1296+ proxySock.close(); 1297+ } else if (reply.indexOf("HTTP/1.") < 0 && reply.indexOf(" 200") < 0) { 1298+ proxySock.close(); 1299+ proxySock = psocket(proxyHost, proxyPort); 1300+ if (proxySock == null) { 1301+ dbg("2-a sadly, returning a null socket"); 1302+ return; 1303+ } 1304+ } 1305+ } catch(Exception e) { 1306+ dbg("some proxy socket problem: " + e.getMessage()); 1307+ } 1308+ 1309+ /* read the rest of the HTTP headers */ 1310+ while (true) { 1311+ String line = readline(proxy_is); 1312+ dbg("proxy line: " + line.trim()); 1313+ if (proxy_auth) { 1314+ String uc = line.toLowerCase(); 1315+ if (uc.indexOf("proxy-authenticate:") == 0) { 1316+ if (uc.indexOf(" basic ") >= 0) { 1317+ int idx = uc.indexOf(" realm"); 1318+ if (idx >= 0) { 1319+ proxy_auth_basic_realm = uc.substring(idx+1); 1320+ } 1321+ } 1322+ } 1323+ } 1324+ if (line.equals("\r\n") || line.equals("\n")) { 1325+ break; 1326+ } 1327+ } 1328+ if (!proxy_auth || proxy_auth_basic_realm.equals("")) { 1329+ /* we only try once for the non-password case: */ 1330+ break; 1331+ } 1332+ } 1333+ } 1334+ 1335+ public SSLSocket proxy_socket(SSLSocketFactory factory) { 1336+ Properties props = null; 1337+ String proxyHost = null; 1338+ int proxyPort = 0; 1339+ String proxyHost_nossl = null; 1340+ int proxyPort_nossl = 0; 1341+ String str; 1342+ 1343+ /* see if we can guess the proxy info from Properties: */ 1344+ try { 1345+ props = System.getProperties(); 1346+ } catch (Exception e) { 1347+ /* sandboxed applet might not be able to read it. */ 1348+ dbg("props failed: " + e.getMessage()); 1349+ } 1350+ if (viewer.proxyHost != null) { 1351+ dbg("Using supplied proxy " + viewer.proxyHost + " " + viewer.proxyPort + " applet parameters."); 1352+ proxyHost = viewer.proxyHost; 1353+ if (viewer.proxyPort != null) { 1354+ proxyPort = gint(viewer.proxyPort); 1355+ } else { 1356+ proxyPort = 8080; 1357+ } 1358+ 1359+ } else if (props != null) { 1360+ dbg("\n---------------\nAll props:"); 1361+ props.list(System.out); 1362+ dbg("\n---------------\n\n"); 1363+ 1364+ /* scrape throught properties looking for proxy info: */ 1365+ 1366+ for (Enumeration e = props.propertyNames(); e.hasMoreElements(); ) { 1367+ String s = (String) e.nextElement(); 1368+ String v = System.getProperty(s); 1369+ String s2 = s.toLowerCase(); 1370+ String v2 = v.toLowerCase(); 1371+ 1372+ if (s2.indexOf("proxy.https.host") >= 0) { 1373+ proxyHost = v2; 1374+ continue; 1375+ } 1376+ if (s2.indexOf("proxy.https.port") >= 0) { 1377+ proxyPort = gint(v2); 1378+ continue; 1379+ } 1380+ if (s2.indexOf("proxy.http.host") >= 0) { 1381+ proxyHost_nossl = v2; 1382+ continue; 1383+ } 1384+ if (s2.indexOf("proxy.http.port") >= 0) { 1385+ proxyPort_nossl = gint(v2); 1386+ continue; 1387+ } 1388+ } 1389+ 1390+ for (Enumeration e = props.propertyNames(); e.hasMoreElements(); ) { 1391+ String s = (String) e.nextElement(); 1392+ String v = System.getProperty(s); 1393+ String s2 = s.toLowerCase(); 1394+ String v2 = v.toLowerCase(); 1395+ 1396+ if (proxyHost != null && proxyPort > 0) { 1397+ break; 1398+ } 1399+ 1400+ // look for something like: javaplugin.proxy.config.list = http=10.0.2.1:8082 1401+ if (s2.indexOf("proxy") < 0 && v2.indexOf("proxy") < 0) { 1402+ continue; 1403+ } 1404+ if (v2.indexOf("http") < 0) { 1405+ continue; 1406+ } 1407+ 1408+ String[] pieces = v.split("[,;]"); 1409+ for (int i = 0; i < pieces.length; i++) { 1410+ String p = pieces[i]; 1411+ int j = p.indexOf("https"); 1412+ if (j < 0) { 1413+ j = p.indexOf("http"); 1414+ if (j < 0) { 1415+ continue; 1416+ } 1417+ } 1418+ j = p.indexOf("=", j); 1419+ if (j < 0) { 1420+ continue; 1421+ } 1422+ p = p.substring(j+1); 1423+ String [] hp = p.split(":"); 1424+ if (hp.length != 2) { 1425+ continue; 1426+ } 1427+ if (hp[0].length() > 1 && hp[1].length() > 1) { 1428+ 1429+ proxyPort = gint(hp[1]); 1430+ if (proxyPort < 0) { 1431+ continue; 1432+ } 1433+ proxyHost = new String(hp[0]); 1434+ break; 1435+ } 1436+ } 1437+ } 1438+ } 1439+ if (proxyHost != null) { 1440+ if (proxyHost_nossl != null && proxyPort_nossl > 0) { 1441+ dbg("Using http proxy info instead of https."); 1442+ proxyHost = proxyHost_nossl; 1443+ proxyPort = proxyPort_nossl; 1444+ } 1445+ } 1446+ 1447+ if (proxy_in_use) { 1448+ if (proxy_dialog_host != null && proxy_dialog_port > 0) { 1449+ proxyHost = proxy_dialog_host; 1450+ proxyPort = proxy_dialog_port; 1451+ } 1452+ if (proxyHost != null) { 1453+ dbg("Lucky us! we figured out the Proxy parameters: " + proxyHost + " " + proxyPort); 1454+ } else { 1455+ /* ask user to help us: */ 1456+ ProxyDialog pd = new ProxyDialog(proxyHost, proxyPort); 1457+ pd.queryUser(); 1458+ proxyHost = pd.getHost(); 1459+ proxyPort = pd.getPort(); 1460+ proxy_dialog_host = new String(proxyHost); 1461+ proxy_dialog_port = proxyPort; 1462+ dbg("User said host: " + pd.getHost() + " port: " + pd.getPort()); 1463+ } 1464+ 1465+ proxy_helper(proxyHost, proxyPort); 1466+ if (proxySock == null) { 1467+ return null; 1468+ } 1469+ } else if (viewer.CONNECT != null) { 1470+ dbg("viewer.CONNECT psocket:"); 1471+ proxySock = psocket(host, port); 1472+ if (proxySock == null) { 1473+ dbg("1-b sadly, returning a null socket"); 1474+ return null; 1475+ } 1476+ } 1477+ 1478+ if (viewer.CONNECT != null) { 1479+ String hp = viewer.CONNECT; 1480+ String req2 = "CONNECT " + hp + " HTTP/1.1\r\n" 1481+ + "Host: " + hp + "\r\n\r\n"; 1482+ 1483+ dbg("requesting2: " + req2); 1484+ 1485+ try { 1486+ proxy_os.write(req2.getBytes()); 1487+ String reply = readline(proxy_is); 1488+ 1489+ dbg("proxy replied2: " + reply.trim()); 1490+ 1491+ if (reply.indexOf("HTTP/1.") < 0 && reply.indexOf(" 200") < 0) { 1492+ proxySock.close(); 1493+ proxySock = psocket(proxyHost, proxyPort); 1494+ if (proxySock == null) { 1495+ dbg("2-b sadly, returning a null socket"); 1496+ return null; 1497+ } 1498+ } 1499+ } catch(Exception e) { 1500+ dbg("proxy socket problem-2: " + e.getMessage()); 1501+ } 1502+ 1503+ while (true) { 1504+ String line = readline(proxy_is); 1505+ dbg("proxy line2: " + line.trim()); 1506+ if (line.equals("\r\n") || line.equals("\n")) { 1507+ break; 1508+ } 1509+ } 1510+ } 1511+ 1512+ Socket sslsock = null; 1513+ try { 1514+ sslsock = factory.createSocket(proxySock, host, port, true); 1515+ } catch(Exception e) { 1516+ dbg("sslsock prob: " + e.getMessage()); 1517+ dbg("3 sadly, returning a null socket"); 1518+ } 1519+ 1520+ return (SSLSocket) sslsock; 1521+ } 1522+ 1523+ Socket psocket(String h, int p) { 1524+ Socket psock = null; 1525+ try { 1526+ psock = new Socket(h, p); 1527+ proxy_is = new DataInputStream(new BufferedInputStream( 1528+ psock.getInputStream(), 16384)); 1529+ proxy_os = psock.getOutputStream(); 1530+ } catch(Exception e) { 1531+ dbg("psocket prob: " + e.getMessage()); 1532+ return null; 1533+ } 1534+ 1535+ return psock; 1536+ } 1537+ 1538+ String readline(DataInputStream i) { 1539+ byte[] ba = new byte[1]; 1540+ String s = new String(""); 1541+ ba[0] = 0; 1542+ try { 1543+ while (ba[0] != 0xa) { 1544+ ba[0] = (byte) i.readUnsignedByte(); 1545+ s += new String(ba); 1546+ } 1547+ } catch (Exception e) { 1548+ ; 1549+ } 1550+ return s; 1551+ } 1552+} 1553+ 1554+class TrustDialog implements ActionListener { 1555+ String msg, host, text; 1556+ int port; 1557+ java.security.cert.Certificate[] trustallCerts = null; 1558+ boolean viewing_cert = false; 1559+ boolean trust_this_session = false; 1560+ 1561+ /* 1562+ * this is the gui to show the user the cert and info and ask 1563+ * them if they want to continue using this cert. 1564+ */ 1565+ 1566+ Button ok, cancel, viewcert; 1567+ TextArea textarea; 1568+ Checkbox accept, deny; 1569+ Dialog dialog; 1570+ 1571+ String s1 = "Accept this certificate temporarily for this session"; 1572+ String s2 = "Do not accept this certificate and do not connect to" 1573+ + " this VNC server"; 1574+ String ln = "\n---------------------------------------------------\n\n"; 1575+ 1576+ TrustDialog (String h, int p, java.security.cert.Certificate[] s) { 1577+ host = h; 1578+ port = p; 1579+ trustallCerts = s; 1580+ 1581+ msg = "VNC Server " + host + ":" + port + " Not Verified"; 1582+ } 1583+ 1584+ public boolean queryUser(String reason) { 1585+ 1586+ /* create and display the dialog for unverified cert. */ 1587+ 1588+ Frame frame = new Frame(msg); 1589+ 1590+ dialog = new Dialog(frame, true); 1591+ 1592+ String infostr = ""; 1593+ if (trustallCerts.length == 1) { 1594+ CertInfo ci = new CertInfo(trustallCerts[0]); 1595+ infostr = ci.get_certinfo("all"); 1596+ } 1597+ if (reason != null) { 1598+ reason += "\n\n"; 1599+ } 1600+ 1601+ text = "\n" 1602++ "Unable to verify the identity of\n" 1603++ "\n" 1604++ " " + host + ":" + port + "\n" 1605++ "\n" 1606++ infostr 1607++ "\n" 1608++ "as a trusted VNC server.\n" 1609++ "\n" 1610++ reason 1611++ "In General not being able to verify the VNC Server and/or your seeing this Dialog\n" 1612++ "is due to one of the following:\n" 1613++ "\n" 1614++ " - Your requesting to View the Certificate before accepting.\n" 1615++ "\n" 1616++ " - The VNC server is using a Self-Signed Certificate or a Certificate\n" 1617++ " Authority not recognized by your Web Browser or Java Plugin runtime.\n" 1618++ "\n" 1619++ " - The use of an Apache SSL portal scheme employing CONNECT proxying AND\n" 1620++ " the Apache Web server has a certificate *different* from the VNC server's.\n" 1621++ "\n" 1622++ " - No previously accepted Certificate (via Web Broswer/Java Plugin) could be\n" 1623++ " obtained by this applet to compare the VNC Server Certificate against.\n" 1624++ "\n" 1625++ " - The VNC Server's Certificate does not match the one specified in the\n" 1626++ " supplied 'serverCert' Java Applet Parameter.\n" 1627++ "\n" 1628++ " - A Man-In-The-Middle attack impersonating as the VNC server that you wish\n" 1629++ " to connect to. (Wouldn't that be exciting!!)\n" 1630++ "\n" 1631++ "By safely copying the VNC server's Certificate (or using a common Certificate\n" 1632++ "Authority certificate) you can configure your Web Browser and Java Plugin to\n" 1633++ "automatically authenticate this VNC Server.\n" 1634++ "\n" 1635++ "If you do so, then you will only have to click \"Yes\" when this VNC Viewer\n" 1636++ "applet asks you whether to trust your Browser/Java Plugin's acceptance of the\n" 1637++ "certificate (except for the Apache portal case above where they don't match.)\n" 1638++ "\n" 1639++ "You can also set the applet parameter 'trustUrlVncCert=yes' to automatically\n" 1640++ "accept certificates already accepted/trusted by your Web Browser/Java Plugin,\n" 1641++ "and thereby see no dialog from this VNC Viewer applet.\n" 1642+; 1643+ 1644+ /* the accept / do-not-accept radio buttons: */ 1645+ CheckboxGroup checkbox = new CheckboxGroup(); 1646+ accept = new Checkbox(s1, true, checkbox); 1647+ deny = new Checkbox(s2, false, checkbox); 1648+ 1649+ /* put the checkboxes in a panel: */ 1650+ Panel check = new Panel(); 1651+ check.setLayout(new GridLayout(2, 1)); 1652+ 1653+ check.add(accept); 1654+ check.add(deny); 1655+ 1656+ /* make the 3 buttons: */ 1657+ ok = new Button("OK"); 1658+ cancel = new Button("Cancel"); 1659+ viewcert = new Button("View Certificate"); 1660+ 1661+ ok.addActionListener(this); 1662+ cancel.addActionListener(this); 1663+ viewcert.addActionListener(this); 1664+ 1665+ /* put the buttons in their own panel: */ 1666+ Panel buttonrow = new Panel(); 1667+ buttonrow.setLayout(new FlowLayout(FlowLayout.LEFT)); 1668+ buttonrow.add(viewcert); 1669+ buttonrow.add(ok); 1670+ buttonrow.add(cancel); 1671+ 1672+ /* label at the top: */ 1673+ Label label = new Label(msg, Label.CENTER); 1674+ label.setFont(new Font("Helvetica", Font.BOLD, 16)); 1675+ 1676+ /* textarea in the middle */ 1677+ textarea = new TextArea(text, 38, 64, 1678+ TextArea.SCROLLBARS_VERTICAL_ONLY); 1679+ textarea.setEditable(false); 1680+ 1681+ /* put the two panels in their own panel at bottom: */ 1682+ Panel bot = new Panel(); 1683+ bot.setLayout(new GridLayout(2, 1)); 1684+ bot.add(check); 1685+ bot.add(buttonrow); 1686+ 1687+ /* now arrange things inside the dialog: */ 1688+ dialog.setLayout(new BorderLayout()); 1689+ 1690+ dialog.add("North", label); 1691+ dialog.add("South", bot); 1692+ dialog.add("Center", textarea); 1693+ 1694+ dialog.pack(); 1695+ dialog.resize(dialog.preferredSize()); 1696+ 1697+ dialog.show(); /* block here til OK or Cancel pressed. */ 1698+ 1699+ return trust_this_session; 1700+ } 1701+ 1702+ public synchronized void actionPerformed(ActionEvent evt) { 1703+ 1704+ if (evt.getSource() == viewcert) { 1705+ /* View Certificate button clicked */ 1706+ if (viewing_cert) { 1707+ /* show the original info text: */ 1708+ textarea.setText(text); 1709+ viewcert.setLabel("View Certificate"); 1710+ viewing_cert = false; 1711+ } else { 1712+ int i; 1713+ /* show all (likely just one) certs: */ 1714+ textarea.setText(""); 1715+ for (i=0; i < trustallCerts.length; i++) { 1716+ int j = i + 1; 1717+ textarea.append("Certificate[" + 1718+ j + "]\n\n"); 1719+ textarea.append( 1720+ trustallCerts[i].toString()); 1721+ textarea.append(ln); 1722+ } 1723+ viewcert.setLabel("View Info"); 1724+ viewing_cert = true; 1725+ 1726+ textarea.setCaretPosition(0); 1727+ } 1728+ 1729+ } else if (evt.getSource() == ok) { 1730+ /* OK button clicked */ 1731+ if (accept.getState()) { 1732+ trust_this_session = true; 1733+ } else { 1734+ trust_this_session = false; 1735+ } 1736+ //dialog.dispose(); 1737+ dialog.hide(); 1738+ 1739+ } else if (evt.getSource() == cancel) { 1740+ /* Cancel button clicked */ 1741+ trust_this_session = false; 1742+ 1743+ //dialog.dispose(); 1744+ dialog.hide(); 1745+ } 1746+ } 1747+ 1748+ String get_certinfo() { 1749+ String all = ""; 1750+ String fields[] = {"CN", "OU", "O", "L", "C"}; 1751+ int i; 1752+ if (trustallCerts.length < 1) { 1753+ all = ""; 1754+ return all; 1755+ } 1756+ String cert = trustallCerts[0].toString(); 1757+ 1758+ /* 1759+ * For now we simply scrape the cert string, there must 1760+ * be an API for this... perhaps optionValue? 1761+ */ 1762+ 1763+ for (i=0; i < fields.length; i++) { 1764+ int f, t, t1, t2; 1765+ String sub, mat = fields[i] + "="; 1766+ 1767+ f = cert.indexOf(mat, 0); 1768+ if (f > 0) { 1769+ t1 = cert.indexOf(", ", f); 1770+ t2 = cert.indexOf("\n", f); 1771+ if (t1 < 0 && t2 < 0) { 1772+ continue; 1773+ } else if (t1 < 0) { 1774+ t = t2; 1775+ } else if (t2 < 0) { 1776+ t = t1; 1777+ } else if (t1 < t2) { 1778+ t = t1; 1779+ } else { 1780+ t = t2; 1781+ } 1782+ if (t > f) { 1783+ sub = cert.substring(f, t); 1784+ all = all + " " + sub + "\n"; 1785+ } 1786+ } 1787+ } 1788+ return all; 1789+ } 1790+} 1791+ 1792+class ProxyDialog implements ActionListener { 1793+ String guessedHost = null; 1794+ String guessedPort = null; 1795+ /* 1796+ * this is the gui to show the user the cert and info and ask 1797+ * them if they want to continue using this cert. 1798+ */ 1799+ 1800+ Button ok; 1801+ Dialog dialog; 1802+ TextField entry; 1803+ String reply = ""; 1804+ 1805+ ProxyDialog (String h, int p) { 1806+ guessedHost = h; 1807+ try { 1808+ guessedPort = Integer.toString(p); 1809+ } catch (Exception e) { 1810+ guessedPort = "8080"; 1811+ } 1812+ } 1813+ 1814+ public void queryUser() { 1815+ 1816+ /* create and display the dialog for unverified cert. */ 1817+ 1818+ Frame frame = new Frame("Need Proxy host:port"); 1819+ 1820+ dialog = new Dialog(frame, true); 1821+ 1822+ 1823+ Label label = new Label("Please Enter your https Proxy info as host:port", Label.CENTER); 1824+ //label.setFont(new Font("Helvetica", Font.BOLD, 16)); 1825+ entry = new TextField(30); 1826+ ok = new Button("OK"); 1827+ ok.addActionListener(this); 1828+ 1829+ String guess = ""; 1830+ if (guessedHost != null) { 1831+ guess = guessedHost + ":" + guessedPort; 1832+ } 1833+ entry.setText(guess); 1834+ 1835+ dialog.setLayout(new BorderLayout()); 1836+ dialog.add("North", label); 1837+ dialog.add("Center", entry); 1838+ dialog.add("South", ok); 1839+ dialog.pack(); 1840+ dialog.resize(dialog.preferredSize()); 1841+ 1842+ dialog.show(); /* block here til OK or Cancel pressed. */ 1843+ return; 1844+ } 1845+ 1846+ public String getHost() { 1847+ int i = reply.indexOf(":"); 1848+ if (i < 0) { 1849+ return "unknown"; 1850+ } 1851+ String h = reply.substring(0, i); 1852+ return h; 1853+ } 1854+ 1855+ public int getPort() { 1856+ int i = reply.indexOf(":"); 1857+ int p = 8080; 1858+ if (i < 0) { 1859+ return p; 1860+ } 1861+ i++; 1862+ String ps = reply.substring(i); 1863+ try { 1864+ Integer I = new Integer(ps); 1865+ p = I.intValue(); 1866+ } catch (Exception e) { 1867+ ; 1868+ } 1869+ return p; 1870+ } 1871+ 1872+ public synchronized void actionPerformed(ActionEvent evt) { 1873+ System.out.println(evt.getActionCommand()); 1874+ if (evt.getSource() == ok) { 1875+ reply = entry.getText(); 1876+ //dialog.dispose(); 1877+ dialog.hide(); 1878+ } 1879+ } 1880+} 1881+ 1882+class ProxyPasswdDialog implements ActionListener { 1883+ String guessedHost = null; 1884+ String guessedPort = null; 1885+ String guessedUser = null; 1886+ String guessedPasswd = null; 1887+ String realm = null; 1888+ /* 1889+ * this is the gui to show the user the cert and info and ask 1890+ * them if they want to continue using this cert. 1891+ */ 1892+ 1893+ Button ok; 1894+ Dialog dialog; 1895+ TextField entry1; 1896+ TextField entry2; 1897+ String reply1 = ""; 1898+ String reply2 = ""; 1899+ 1900+ ProxyPasswdDialog (String h, int p, String realm) { 1901+ guessedHost = h; 1902+ try { 1903+ guessedPort = Integer.toString(p); 1904+ } catch (Exception e) { 1905+ guessedPort = "8080"; 1906+ } 1907+ this.realm = realm; 1908+ } 1909+ 1910+ public void queryUser() { 1911+ 1912+ /* create and display the dialog for unverified cert. */ 1913+ 1914+ Frame frame = new Frame("Proxy Requires Username and Password"); 1915+ 1916+ dialog = new Dialog(frame, true); 1917+ 1918+ //Label label = new Label("Please Enter your Web Proxy Username in the top Entry and Password in the bottom Entry", Label.CENTER); 1919+ 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); 1920+ entry1 = new TextField(30); 1921+ entry2 = new TextField(30); 1922+ entry2.setEchoChar('*'); 1923+ ok = new Button("OK"); 1924+ ok.addActionListener(this); 1925+ 1926+ dialog.setLayout(new BorderLayout()); 1927+ dialog.add("North", label); 1928+ dialog.add("Center", entry1); 1929+ dialog.add("South", entry2); 1930+ dialog.add("East", ok); 1931+ dialog.pack(); 1932+ dialog.resize(dialog.preferredSize()); 1933+ 1934+ dialog.show(); /* block here til OK or Cancel pressed. */ 1935+ return; 1936+ } 1937+ 1938+ public String getAuth() { 1939+ return reply1 + ":" + reply2; 1940+ } 1941+ 1942+ public synchronized void actionPerformed(ActionEvent evt) { 1943+ System.out.println(evt.getActionCommand()); 1944+ if (evt.getSource() == ok) { 1945+ reply1 = entry1.getText(); 1946+ reply2 = entry2.getText(); 1947+ //dialog.dispose(); 1948+ dialog.hide(); 1949+ } 1950+ } 1951+} 1952+ 1953+class ClientCertDialog implements ActionListener { 1954+ 1955+ Button ok; 1956+ Dialog dialog; 1957+ TextField entry; 1958+ String reply = ""; 1959+ 1960+ ClientCertDialog() { 1961+ ; 1962+ } 1963+ 1964+ public String queryUser() { 1965+ 1966+ /* create and display the dialog for unverified cert. */ 1967+ 1968+ Frame frame = new Frame("Enter SSL Client Cert+Key String"); 1969+ 1970+ dialog = new Dialog(frame, true); 1971+ 1972+ 1973+ Label label = new Label("Please Enter the SSL Client Cert+Key String 308204c0...,...522d2d0a", Label.CENTER); 1974+ entry = new TextField(30); 1975+ ok = new Button("OK"); 1976+ ok.addActionListener(this); 1977+ 1978+ dialog.setLayout(new BorderLayout()); 1979+ dialog.add("North", label); 1980+ dialog.add("Center", entry); 1981+ dialog.add("South", ok); 1982+ dialog.pack(); 1983+ dialog.resize(dialog.preferredSize()); 1984+ 1985+ dialog.show(); /* block here til OK or Cancel pressed. */ 1986+ return reply; 1987+ } 1988+ 1989+ public synchronized void actionPerformed(ActionEvent evt) { 1990+ System.out.println(evt.getActionCommand()); 1991+ if (evt.getSource() == ok) { 1992+ reply = entry.getText(); 1993+ //dialog.dispose(); 1994+ dialog.hide(); 1995+ } 1996+ } 1997+} 1998+ 1999+class BrowserCertsDialog implements ActionListener { 2000+ Button yes, no; 2001+ Dialog dialog; 2002+ String vncServer; 2003+ String hostport; 2004+ public boolean showCertDialog = true; 2005+ 2006+ BrowserCertsDialog(String serv, String hp) { 2007+ vncServer = serv; 2008+ hostport = hp; 2009+ } 2010+ 2011+ public void queryUser() { 2012+ 2013+ /* create and display the dialog for unverified cert. */ 2014+ 2015+ Frame frame = new Frame("Use Browser/JVM Certs?"); 2016+ 2017+ dialog = new Dialog(frame, true); 2018+ 2019+ String m = ""; 2020+m += "\n"; 2021+m += "This VNC Viewer applet does not have its own keystore to track\n"; 2022+m += "SSL certificates, and so cannot authenticate the certificate\n"; 2023+m += "of the VNC Server:\n"; 2024+m += "\n"; 2025+m += " " + hostport + "\n\n " + vncServer + "\n"; 2026+m += "\n"; 2027+m += "on its own.\n"; 2028+m += "\n"; 2029+m += "However, it has noticed that your Web Browser and/or Java VM Plugin\n"; 2030+m += "has previously accepted the same certificate. You may have set\n"; 2031+m += "this up permanently or just for this session, or the server\n"; 2032+m += "certificate was signed by a CA cert that your Web Browser or\n"; 2033+m += "Java VM Plugin has.\n"; 2034+m += "\n"; 2035+m += "If the VNC Server connection times out while you are reading this\n"; 2036+m += "dialog, then restart the connection and try again.\n"; 2037+m += "\n"; 2038+m += "Should this VNC Viewer applet now connect to the above VNC server?\n"; 2039+m += "\n"; 2040+ 2041+ TextArea textarea = new TextArea(m, 22, 64, 2042+ TextArea.SCROLLBARS_VERTICAL_ONLY); 2043+ textarea.setEditable(false); 2044+ yes = new Button("Yes"); 2045+ yes.addActionListener(this); 2046+ no = new Button("No, Let Me See the Certificate."); 2047+ no.addActionListener(this); 2048+ 2049+ dialog.setLayout(new BorderLayout()); 2050+ dialog.add("North", textarea); 2051+ dialog.add("Center", yes); 2052+ dialog.add("South", no); 2053+ dialog.pack(); 2054+ dialog.resize(dialog.preferredSize()); 2055+ 2056+ dialog.show(); /* block here til Yes or No pressed. */ 2057+ System.out.println("done show()"); 2058+ return; 2059+ } 2060+ 2061+ public synchronized void actionPerformed(ActionEvent evt) { 2062+ System.out.println(evt.getActionCommand()); 2063+ if (evt.getSource() == yes) { 2064+ showCertDialog = false; 2065+ //dialog.dispose(); 2066+ dialog.hide(); 2067+ } else if (evt.getSource() == no) { 2068+ showCertDialog = true; 2069+ //dialog.dispose(); 2070+ dialog.hide(); 2071+ } 2072+ System.out.println("done actionPerformed()"); 2073+ } 2074+} 2075+ 2076+class CertInfo { 2077+ String fields[] = {"CN", "OU", "O", "L", "C"}; 2078+ java.security.cert.Certificate cert; 2079+ String certString = ""; 2080+ 2081+ CertInfo(java.security.cert.Certificate c) { 2082+ cert = c; 2083+ certString = cert.toString(); 2084+ } 2085+ 2086+ String get_certinfo(String which) { 2087+ int i; 2088+ String cs = new String(certString); 2089+ String all = ""; 2090+ 2091+ /* 2092+ * For now we simply scrape the cert string, there must 2093+ * be an API for this... perhaps optionValue? 2094+ */ 2095+ for (i=0; i < fields.length; i++) { 2096+ int f, t, t1, t2; 2097+ String sub, mat = fields[i] + "="; 2098+ 2099+ f = cs.indexOf(mat, 0); 2100+ if (f > 0) { 2101+ t1 = cs.indexOf(", ", f); 2102+ t2 = cs.indexOf("\n", f); 2103+ if (t1 < 0 && t2 < 0) { 2104+ continue; 2105+ } else if (t1 < 0) { 2106+ t = t2; 2107+ } else if (t2 < 0) { 2108+ t = t1; 2109+ } else if (t1 < t2) { 2110+ t = t1; 2111+ } else { 2112+ t = t2; 2113+ } 2114+ if (t > f) { 2115+ sub = cs.substring(f, t); 2116+ all = all + " " + sub + "\n"; 2117+ if (which.equals(fields[i])) { 2118+ return sub; 2119+ } 2120+ } 2121+ } 2122+ } 2123+ if (which.equals("all")) { 2124+ return all; 2125+ } else { 2126+ return ""; 2127+ } 2128+ } 2129+} 2130+ 2131+class Base64Coder { 2132+ 2133+ // Mapping table from 6-bit nibbles to Base64 characters. 2134+ private static char[] map1 = new char[64]; 2135+ static { 2136+ int i=0; 2137+ for (char c='A'; c<='Z'; c++) map1[i++] = c; 2138+ for (char c='a'; c<='z'; c++) map1[i++] = c; 2139+ for (char c='0'; c<='9'; c++) map1[i++] = c; 2140+ map1[i++] = '+'; map1[i++] = '/'; } 2141+ 2142+ // Mapping table from Base64 characters to 6-bit nibbles. 2143+ private static byte[] map2 = new byte[128]; 2144+ static { 2145+ for (int i=0; i<map2.length; i++) map2[i] = -1; 2146+ for (int i=0; i<64; i++) map2[map1[i]] = (byte)i; } 2147+ 2148+ /** 2149+ * Encodes a string into Base64 format. 2150+ * No blanks or line breaks are inserted. 2151+ * @param s a String to be encoded. 2152+ * @return A String with the Base64 encoded data. 2153+ */ 2154+ public static String encodeString (String s) { 2155+ return new String(encode(s.getBytes())); } 2156+ 2157+ /** 2158+ * Encodes a byte array into Base64 format. 2159+ * No blanks or line breaks are inserted. 2160+ * @param in an array containing the data bytes to be encoded. 2161+ * @return A character array with the Base64 encoded data. 2162+ */ 2163+ public static char[] encode (byte[] in) { 2164+ return encode(in,in.length); } 2165+ 2166+ /** 2167+ * Encodes a byte array into Base64 format. 2168+ * No blanks or line breaks are inserted. 2169+ * @param in an array containing the data bytes to be encoded. 2170+ * @param iLen number of bytes to process in <code>in</code>. 2171+ * @return A character array with the Base64 encoded data. 2172+ */ 2173+ public static char[] encode (byte[] in, int iLen) { 2174+ int oDataLen = (iLen*4+2)/3; // output length without padding 2175+ int oLen = ((iLen+2)/3)*4; // output length including padding 2176+ char[] out = new char[oLen]; 2177+ int ip = 0; 2178+ int op = 0; 2179+ while (ip < iLen) { 2180+ int i0 = in[ip++] & 0xff; 2181+ int i1 = ip < iLen ? in[ip++] & 0xff : 0; 2182+ int i2 = ip < iLen ? in[ip++] & 0xff : 0; 2183+ int o0 = i0 >>> 2; 2184+ int o1 = ((i0 & 3) << 4) | (i1 >>> 4); 2185+ int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6); 2186+ int o3 = i2 & 0x3F; 2187+ out[op++] = map1[o0]; 2188+ out[op++] = map1[o1]; 2189+ out[op] = op < oDataLen ? map1[o2] : '='; op++; 2190+ out[op] = op < oDataLen ? map1[o3] : '='; op++; } 2191+ return out; } 2192+ 2193+ /** 2194+ * Decodes a string from Base64 format. 2195+ * @param s a Base64 String to be decoded. 2196+ * @return A String containing the decoded data. 2197+ * @throws IllegalArgumentException if the input is not valid Base64 encoded data. 2198+ */ 2199+ public static String decodeString (String s) { 2200+ return new String(decode(s)); } 2201+ 2202+ /** 2203+ * Decodes a byte array from Base64 format. 2204+ * @param s a Base64 String to be decoded. 2205+ * @return An array containing the decoded data bytes. 2206+ * @throws IllegalArgumentException if the input is not valid Base64 encoded data. 2207+ */ 2208+ public static byte[] decode (String s) { 2209+ return decode(s.toCharArray()); } 2210+ 2211+ /** 2212+ * Decodes a byte array from Base64 format. 2213+ * No blanks or line breaks are allowed within the Base64 encoded data. 2214+ * @param in a character array containing the Base64 encoded data. 2215+ * @return An array containing the decoded data bytes. 2216+ * @throws IllegalArgumentException if the input is not valid Base64 encoded data. 2217+ */ 2218+ public static byte[] decode (char[] in) { 2219+ int iLen = in.length; 2220+ if (iLen%4 != 0) throw new IllegalArgumentException ("Length of Base64 encoded input string is not a multiple of 4."); 2221+ while (iLen > 0 && in[iLen-1] == '=') iLen--; 2222+ int oLen = (iLen*3) / 4; 2223+ byte[] out = new byte[oLen]; 2224+ int ip = 0; 2225+ int op = 0; 2226+ while (ip < iLen) { 2227+ int i0 = in[ip++]; 2228+ int i1 = in[ip++]; 2229+ int i2 = ip < iLen ? in[ip++] : 'A'; 2230+ int i3 = ip < iLen ? in[ip++] : 'A'; 2231+ if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127) 2232+ throw new IllegalArgumentException ("Illegal character in Base64 encoded data."); 2233+ int b0 = map2[i0]; 2234+ int b1 = map2[i1]; 2235+ int b2 = map2[i2]; 2236+ int b3 = map2[i3]; 2237+ if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0) 2238+ throw new IllegalArgumentException ("Illegal character in Base64 encoded data."); 2239+ int o0 = ( b0 <<2) | (b1>>>4); 2240+ int o1 = ((b1 & 0xf)<<4) | (b2>>>2); 2241+ int o2 = ((b2 & 3)<<6) | b3; 2242+ out[op++] = (byte)o0; 2243+ if (op<oLen) out[op++] = (byte)o1; 2244+ if (op<oLen) out[op++] = (byte)o2; } 2245+ return out; } 2246+ 2247+ // Dummy constructor. 2248+ private Base64Coder() {} 2249+ 2250+} 2251diff -Naur vnc_javasrc.orig/VncCanvas.java vnc_javasrc/VncCanvas.java 2252--- vnc_javasrc.orig/VncCanvas.java 2004-10-10 02:15:54.000000000 -0400 2253+++ vnc_javasrc/VncCanvas.java 2010-11-30 21:01:15.000000000 -0500 2254@@ -28,13 +28,14 @@ 2255 import java.lang.*; 2256 import java.util.zip.*; 2257 2258+import java.util.Collections; 2259 2260 // 2261 // VncCanvas is a subclass of Canvas which draws a VNC desktop on it. 2262 // 2263 2264 class VncCanvas extends Canvas 2265- implements KeyListener, MouseListener, MouseMotionListener { 2266+ implements KeyListener, MouseListener, MouseMotionListener, MouseWheelListener { 2267 2268 VncViewer viewer; 2269 RfbProto rfb; 2270@@ -81,6 +82,20 @@ 2271 cm8 = new DirectColorModel(8, 7, (7 << 3), (3 << 6)); 2272 cm24 = new DirectColorModel(24, 0xFF0000, 0x00FF00, 0x0000FF); 2273 2274+ // kludge to not show any Java cursor in the canvas since we are 2275+ // showing the soft cursor (should be a user setting...) 2276+ Cursor dot = Toolkit.getDefaultToolkit().createCustomCursor( 2277+ Toolkit.getDefaultToolkit().createImage(new byte[4]), new Point(0,0), 2278+ "dot"); 2279+ this.setCursor(dot); 2280+ 2281+ // while we are at it... get rid of the keyboard traversals that 2282+ // make it so we can't type a Tab character: 2283+ this.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, 2284+ Collections.EMPTY_SET); 2285+ this.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, 2286+ Collections.EMPTY_SET); 2287+ 2288 colors = new Color[256]; 2289 for (int i = 0; i < 256; i++) 2290 colors[i] = new Color(cm8.getRGB(i)); 2291@@ -169,6 +184,7 @@ 2292 inputEnabled = true; 2293 addMouseListener(this); 2294 addMouseMotionListener(this); 2295+ addMouseWheelListener(this); 2296 if (viewer.showControls) { 2297 viewer.buttonPanel.enableRemoteAccessControls(true); 2298 } 2299@@ -177,6 +193,7 @@ 2300 inputEnabled = false; 2301 removeMouseListener(this); 2302 removeMouseMotionListener(this); 2303+ removeMouseWheelListener(this); 2304 if (viewer.showControls) { 2305 viewer.buttonPanel.enableRemoteAccessControls(false); 2306 } 2307@@ -1190,6 +1207,9 @@ 2308 public void mouseDragged(MouseEvent evt) { 2309 processLocalMouseEvent(evt, true); 2310 } 2311+ public void mouseWheelMoved(MouseWheelEvent evt) { 2312+ processLocalMouseWheelEvent(evt); 2313+ } 2314 2315 public void processLocalKeyEvent(KeyEvent evt) { 2316 if (viewer.rfb != null && rfb.inNormalProtocol) { 2317@@ -1221,6 +1241,19 @@ 2318 evt.consume(); 2319 } 2320 2321+ public void processLocalMouseWheelEvent(MouseWheelEvent evt) { 2322+ if (viewer.rfb != null && rfb.inNormalProtocol) { 2323+ synchronized(rfb) { 2324+ try { 2325+ rfb.writeWheelEvent(evt); 2326+ } catch (Exception e) { 2327+ e.printStackTrace(); 2328+ } 2329+ rfb.notify(); 2330+ } 2331+ } 2332+ } 2333+ 2334 public void processLocalMouseEvent(MouseEvent evt, boolean moved) { 2335 if (viewer.rfb != null && rfb.inNormalProtocol) { 2336 if (moved) { 2337@@ -1387,9 +1420,9 @@ 2338 result = cm8.getRGB(pixBuf[i]); 2339 } else { 2340 result = 0xFF000000 | 2341- (pixBuf[i * 4 + 1] & 0xFF) << 16 | 2342- (pixBuf[i * 4 + 2] & 0xFF) << 8 | 2343- (pixBuf[i * 4 + 3] & 0xFF); 2344+ (pixBuf[i * 4 + 2] & 0xFF) << 16 | 2345+ (pixBuf[i * 4 + 1] & 0xFF) << 8 | 2346+ (pixBuf[i * 4 + 0] & 0xFF); 2347 } 2348 } else { 2349 result = 0; // Transparent pixel 2350@@ -1403,9 +1436,9 @@ 2351 result = cm8.getRGB(pixBuf[i]); 2352 } else { 2353 result = 0xFF000000 | 2354- (pixBuf[i * 4 + 1] & 0xFF) << 16 | 2355- (pixBuf[i * 4 + 2] & 0xFF) << 8 | 2356- (pixBuf[i * 4 + 3] & 0xFF); 2357+ (pixBuf[i * 4 + 2] & 0xFF) << 16 | 2358+ (pixBuf[i * 4 + 1] & 0xFF) << 8 | 2359+ (pixBuf[i * 4 + 0] & 0xFF); 2360 } 2361 } else { 2362 result = 0; // Transparent pixel 2363diff -Naur vnc_javasrc.orig/VncViewer.java vnc_javasrc/VncViewer.java 2364--- vnc_javasrc.orig/VncViewer.java 2004-03-04 08:34:25.000000000 -0500 2365+++ vnc_javasrc/VncViewer.java 2010-03-27 17:57:04.000000000 -0400 2366@@ -29,6 +29,7 @@ 2367 import java.awt.event.*; 2368 import java.io.*; 2369 import java.net.*; 2370+import java.util.*; 2371 2372 public class VncViewer extends java.applet.Applet 2373 implements java.lang.Runnable, WindowListener { 2374@@ -80,7 +81,7 @@ 2375 // Variables read from parameter values. 2376 String socketFactory; 2377 String host; 2378- int port; 2379+ int port, vncserverport; 2380 boolean showControls; 2381 boolean offerRelogin; 2382 boolean showOfflineDesktop; 2383@@ -88,6 +89,24 @@ 2384 int deferCursorUpdates; 2385 int deferUpdateRequests; 2386 2387+ boolean disableSSL; 2388+ boolean GET; 2389+ String CONNECT; 2390+ String urlPrefix; 2391+ String httpsPort; 2392+ String oneTimeKey; 2393+ String serverCert; 2394+ String proxyHost; 2395+ String proxyPort; 2396+ boolean forceProxy; 2397+ boolean ignoreProxy; 2398+ boolean trustAllVncCerts; 2399+ boolean trustUrlVncCert; 2400+ boolean debugCerts; 2401+ boolean debugKeyboard; 2402+ boolean mapF5_to_atsign; 2403+ boolean forbid_Ctrl_Alt; 2404+ 2405 // Reference to this applet for inter-applet communication. 2406 public static java.applet.Applet refApplet; 2407 2408@@ -282,10 +301,24 @@ 2409 validate(); 2410 } 2411 2412- while (!tryAuthenticate()) { 2413- authenticator.retry(); 2414- authenticatorUnixLogin.retry(); 2415- } 2416+ if (false) { 2417+ /* a bug on retries: 'Error: bad position: 8' sun.awt.X11.XTextFieldPeer.setCaretPosition(XTextFieldPeer.java:215) */ 2418+ while (!tryAuthenticate()) { 2419+ authenticator.retry(); 2420+ authenticatorUnixLogin.retry(); 2421+ } 2422+ } else { 2423+ /* just try once and not forever... */ 2424+ if (!tryAuthenticate()) { 2425+ showConnectionStatus("Authentication Failed."); 2426+ showMessage("Authentication Failed."); 2427+ if (!offerRelogin) { 2428+ fatalError("auth failed."); 2429+ } 2430+ } else { 2431+ //showConnectionStatus("Authentication OK."); 2432+ } 2433+ } 2434 } 2435 2436 2437@@ -428,7 +461,10 @@ 2438 gbc.ipadx = 100; 2439 gbc.ipady = 50; 2440 gridbag.setConstraints(authPanel, gbc); 2441+ try { 2442 vncContainer.add(authPanel); 2443+ } catch (Exception e) { 2444+ } 2445 2446 if (inSeparateFrame) { 2447 vncFrame.pack(); 2448@@ -590,9 +626,28 @@ 2449 fatalError("HOST parameter not specified"); 2450 } 2451 } 2452+ Date d = new Date(); 2453+ System.out.println("-\nSSL VNC Java Applet starting. " + d); 2454 2455- String str = readParameter("PORT", true); 2456- port = Integer.parseInt(str); 2457+ port = 0; 2458+ String str = readParameter("PORT", false); 2459+ if (str != null) { 2460+ port = Integer.parseInt(str); 2461+ } 2462+ // When there is a proxy VNCSERVERPORT may be inaccessible (inside firewall). 2463+ vncserverport = 0; 2464+ str = readParameter("VNCSERVERPORT", false); 2465+ if (str != null) { 2466+ vncserverport = Integer.parseInt(str); 2467+ } 2468+ if (port == 0 && vncserverport == 0) { 2469+ fatalError("Neither PORT nor VNCSERVERPORT parameters specified"); 2470+ } 2471+ if (port == 0) { 2472+ // Nevertheless, fall back to vncserverport if we have to. 2473+ System.out.println("using vncserverport: '" + vncserverport + "' for PORT."); 2474+ port = vncserverport; 2475+ } 2476 2477 if (inAnApplet) { 2478 str = readParameter("Open New Window", false); 2479@@ -626,6 +681,121 @@ 2480 2481 // SocketFactory. 2482 socketFactory = readParameter("SocketFactory", false); 2483+ 2484+ // SSL 2485+ disableSSL = false; 2486+ str = readParameter("DisableSSL", false); 2487+ if (str != null && str.equalsIgnoreCase("Yes")) 2488+ disableSSL = true; 2489+ 2490+ httpsPort = readParameter("httpsPort", false); 2491+ 2492+ // Extra GET, CONNECT string: 2493+ CONNECT = readParameter("CONNECT", false); 2494+ if (CONNECT != null) { 2495+ CONNECT = CONNECT.replaceAll(" ", ":"); 2496+ } 2497+ 2498+ GET = false; 2499+ str = readParameter("GET", false); 2500+ if (str != null && str.equalsIgnoreCase("Yes")) { 2501+ GET = true; 2502+ } 2503+ if (str != null && str.equalsIgnoreCase("1")) { 2504+ GET = true; 2505+ } 2506+ 2507+ urlPrefix = readParameter("urlPrefix", false); 2508+ if (urlPrefix != null) { 2509+ urlPrefix = urlPrefix.replaceAll("%2F", "/"); 2510+ urlPrefix = urlPrefix.replaceAll("%2f", "/"); 2511+ urlPrefix = urlPrefix.replaceAll("_2F_", "/"); 2512+ if (urlPrefix.indexOf("/") != 0) { 2513+ urlPrefix = "/" + urlPrefix; 2514+ } 2515+ } else { 2516+ urlPrefix = ""; 2517+ } 2518+ System.out.println("urlPrefix: '" + urlPrefix + "'"); 2519+ 2520+ oneTimeKey = readParameter("oneTimeKey", false); 2521+ if (oneTimeKey != null) { 2522+ System.out.println("oneTimeKey is set."); 2523+ } 2524+ 2525+ serverCert = readParameter("serverCert", false); 2526+ if (serverCert != null) { 2527+ System.out.println("serverCert is set."); 2528+ } 2529+ 2530+ forceProxy = false; 2531+ proxyHost = null; 2532+ proxyPort = null; 2533+ str = readParameter("forceProxy", false); 2534+ if (str != null) { 2535+ if (str.equalsIgnoreCase("Yes")) { 2536+ forceProxy = true; 2537+ } else if (str.equalsIgnoreCase("No")) { 2538+ forceProxy = false; 2539+ } else { 2540+ forceProxy = true; 2541+ String[] pieces = str.split(" "); 2542+ proxyHost = new String(pieces[0]); 2543+ if (pieces.length >= 2) { 2544+ proxyPort = new String(pieces[1]); 2545+ } else { 2546+ proxyPort = new String("8080"); 2547+ } 2548+ } 2549+ } 2550+ str = readParameter("proxyHost", false); 2551+ if (str != null) { 2552+ proxyHost = new String(str); 2553+ } 2554+ str = readParameter("proxyPort", false); 2555+ if (str != null) { 2556+ proxyPort = new String(str); 2557+ } 2558+ if (proxyHost != null && proxyPort == null) { 2559+ proxyPort = new String("8080"); 2560+ } 2561+ 2562+ ignoreProxy = false; 2563+ str = readParameter("ignoreProxy", false); 2564+ if (str != null && str.equalsIgnoreCase("Yes")) { 2565+ ignoreProxy = true; 2566+ } 2567+ 2568+ trustAllVncCerts = false; 2569+ str = readParameter("trustAllVncCerts", false); 2570+ if (str != null && str.equalsIgnoreCase("Yes")) { 2571+ trustAllVncCerts = true; 2572+ } 2573+ trustUrlVncCert = false; 2574+ str = readParameter("trustUrlVncCert", false); 2575+ if (str != null && str.equalsIgnoreCase("Yes")) { 2576+ trustUrlVncCert = true; 2577+ } 2578+ debugCerts = false; 2579+ str = readParameter("debugCerts", false); 2580+ if (str != null && str.equalsIgnoreCase("Yes")) { 2581+ debugCerts = true; 2582+ } 2583+ debugKeyboard = false; 2584+ str = readParameter("debugKeyboard", false); 2585+ if (str != null && str.equalsIgnoreCase("Yes")) { 2586+ debugKeyboard = true; 2587+ } 2588+ mapF5_to_atsign = false; 2589+ str = readParameter("mapF5_to_atsign", false); 2590+ if (str != null && str.equalsIgnoreCase("Yes")) { 2591+ mapF5_to_atsign = true; 2592+ } 2593+ forbid_Ctrl_Alt = false; 2594+ str = readParameter("forbid_Ctrl_Alt", false); 2595+ if (str != null && str.equalsIgnoreCase("Yes")) { 2596+ forbid_Ctrl_Alt = true; 2597+ } 2598 } 2599 2600 public String readParameter(String name, boolean required) { 2601