You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libtdevnc/classes/ssl/tightvnc-1.3dev7_javasrc-vn...

574 lines
16 KiB

diff -x VncCanvas.java -Naur vnc_javasrc.orig/Makefile vnc_javasrc/Makefile
--- vnc_javasrc.orig/Makefile 2004-03-04 08:34:25.000000000 -0500
+++ vnc_javasrc/Makefile 2006-03-26 17:29:25.000000000 -0500
@@ -15,25 +15,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) -target 1.4 -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 -x VncCanvas.java -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 2006-03-27 22:26:25.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 {
diff -x VncCanvas.java -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 2006-03-27 20:45:59.000000000 -0500
@@ -0,0 +1,481 @@
+/*
+ * SSLSocketToMe.java: add SSL encryption to Java VNC Viewer.
+ *
+ * Copyright (c) 2006 Karl J. Runge <runge@karlrunge.com>
+ * 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.
+ *
+ * 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.security.cert.*;
+import java.util.Vector;
+
+import java.awt.*;
+import java.awt.event.*;
+
+public class SSLSocketToMe {
+
+ /* basic member data: */
+ String host;
+ int port;
+ VncViewer viewer;
+ boolean debug = true;
+
+ /* sockets */
+ SSLSocket socket = null;
+ SSLSocketFactory factory;
+
+ /* trust contexts */
+ SSLContext trustall_ctx;
+ SSLContext trustone_ctx;
+ TrustManager[] trustAllCerts;
+ TrustManager[] trustOneCert;
+
+ /* cert(s) we retrieve from VNC server */
+ java.security.cert.Certificate[] serverCerts = null;
+
+ SSLSocketToMe(String h, int p, VncViewer v) throws Exception {
+ host = h;
+ port = p;
+ viewer = v;
+
+ /* we will first try default factory for certification: */
+
+ factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
+
+ dbg("SSL startup: " + host + " " + port);
+
+ /* create trust managers used if initial handshake fails: */
+
+ trustAllCerts = new TrustManager[] {
+ /*
+ * this one accepts everything.
+ */
+ 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 */
+ }
+ }
+ };
+
+ trustOneCert = new TrustManager[] {
+ /*
+ * this one accepts only the retrieved server cert.
+ */
+ 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");
+ }
+ public void checkServerTrusted(
+ java.security.cert.X509Certificate[] certs,
+ String authType) throws CertificateException {
+ if (serverCerts == null) {
+ throw new CertificateException(
+ "No Server Certs array.");
+ }
+ if (serverCerts.length < 1) {
+ throw new CertificateException(
+ "No Server Certs.");
+ }
+ if (! serverCerts[0].equals(certs[0])) {
+ throw new CertificateException(
+ "Server Cert Changed.");
+ }
+ dbg("serverCerts[0] matches certs[0]");
+ }
+ }
+ };
+
+ /*
+ * They are used:
+ *
+ * 1) to retrieve the server cert in case of failure to
+ * display it to the user.
+ * 2) to subsequently connect to the server if user agrees.
+ */
+
+ /* trust all certs: */
+ try {
+ trustall_ctx = SSLContext.getInstance("SSL");
+ trustall_ctx.init(null, trustAllCerts, new
+ java.security.SecureRandom());
+
+ } catch (Exception e) {
+ String msg = "SSL trustall_ctx FAILED.";
+ dbg(msg);
+ throw new Exception(msg);
+ }
+
+ /* trust the one cert from server: */
+ try {
+ trustone_ctx = SSLContext.getInstance("SSL");
+ trustone_ctx.init(null, trustOneCert, new
+ java.security.SecureRandom());
+
+ } catch (Exception e) {
+ String msg = "SSL trustone_ctx FAILED.";
+ dbg(msg);
+ throw new Exception(msg);
+ }
+ }
+
+ public Socket connectSock() throws IOException {
+
+ /* now connect to host:port */
+ socket = (SSLSocket) factory.createSocket(host, port);
+
+ try {
+ /*
+ * Verified the first time! How can that be? ;-)
+ * They actually went thru the trouble to set it up?
+ */
+ socket.startHandshake();
+ dbg("Server Connection Verified.");
+
+ } catch (Exception ehand) {
+ dbg("Could not automatically verify Server.");
+
+ socket.close();
+
+ /*
+ * Reconnect, trusting any cert, so we can grab
+ * the cert to show it to the user. The connection
+ * is not used for anything else.
+ */
+ factory = trustall_ctx.getSocketFactory();
+ socket = (SSLSocket) factory.createSocket(host, port);
+
+ try {
+ socket.startHandshake();
+ dbg("TrustAll Server Connection Verified.");
+
+ /* grab the cert: */
+ try {
+ SSLSession sess = socket.getSession();
+ serverCerts = sess.getPeerCertificates();
+ } catch (Exception e) {
+ throw new Exception("Could not get " +
+ "Peer Certificate");
+ }
+
+ /*
+ * close socket now, we will reopen after
+ * dialog if user agrees to use the cert.
+ */
+ socket.close();
+
+ /* dialog with user to accept cert or not: */
+
+ TrustDialog td= new TrustDialog(host, port,
+ serverCerts);
+
+ if (! td.queryUser()) {
+ String msg = "User decided against it.";
+ dbg(msg);
+ throw new IOException(msg);
+ }
+
+ // idea to save certs for reconnections.
+ // not working (RfbProto thread terminates).
+ //viewer.acceptedCerts.addCerts(serverCerts);
+
+ } catch (Exception ehand2) {
+ dbg("** Could not TrustAll Verify Server.");
+
+ throw new IOException(ehand2.getMessage());
+ }
+
+ /*
+ * Now connect a 3rd time, using the cert
+ * retrieved during connection 2 (that the user
+ * likely blindly agreed to).
+ */
+
+ factory = trustone_ctx.getSocketFactory();
+ socket = (SSLSocket) factory.createSocket(host, port);
+
+ try {
+ socket.startHandshake();
+ dbg("TrustAll Server Connection Verified #3.");
+
+ } catch (Exception ehand3) {
+ dbg("** Could not TrustAll Verify Server #3.");
+
+ throw new IOException(ehand3.getMessage());
+ }
+ }
+
+ dbg("SSL returning socket to caller.");
+ return (Socket) socket;
+ }
+
+ private void dbg(String s) {
+ if (debug) {
+ System.out.println(s);
+ }
+ }
+}
+
+class TrustDialog implements ActionListener {
+ String msg, host, text;
+ int port;
+ java.security.cert.Certificate[] serverCerts = 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[] certs) {
+ host = h;
+ port = p;
+ serverCerts = certs;
+
+ msg = "VNC Server " + host + ":" + port + " Not Verified";
+ }
+
+ public boolean queryUser() {
+
+// idea to save certs between connections. not working, everything is
+// cleared after each new connection.
+//
+// public boolean queryUser(VncViewer viewer) {
+// int i, j;
+// java.security.cert.Certificate cert;
+//
+// for (i=0; i < viewer.acceptedCerts.allCerts.size(); i++) {
+// System.out.println("try " + i);
+//
+// cert = (java.security.cert.Certificate)
+// viewer.acceptedCerts.allCerts.elementAt(i);
+//
+// for (j=0; j < serverCerts.length; j++) {
+// System.out.println("try " + i + " " + j);
+// if (serverCerts[j].equals(cert)) {
+// System.out.println("accept previously accepted cert");
+// /* matched, no need for dialog */
+// return true;
+// }
+// }
+// }
+
+ /* create and display the dialog for unverified cert. */
+
+ Frame frame = new Frame(msg);
+
+ dialog = new Dialog(frame, true);
+
+ text = "\n"
++ "Unable to verify the identity of\n"
++ "\n"
++ " " + host + ":" + port + "\n"
++ "\n"
++ get_certinfo()
++ "\n"
++ "as a trusted VNC server.\n"
++ "\n"
++ "This may be due to:\n"
++ "\n"
++ " - The VNC server using a Self-Signed Certificate.\n"
++ "\n"
++ " - The VNC server using a Certificate Authority not recognized by your\n"
++ " Java applet runtime.\n"
++ "\n"
++ " - A Man-In-The-Middle attack impersonating as the VNC server you wish\n"
++ " to connect to.\n"
++ "\n"
++ "By copying the VNC server's Certificate (or using a common Certificate\n"
++ "Authority certificate) you can configure your Java applet runtime to\n"
++ "automatically authenticate the Server.\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, 28, 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 < serverCerts.length; i++) {
+ int j = i + 1;
+ textarea.append("Certificate[" +
+ j + "]\n\n");
+ textarea.append(
+ serverCerts[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();
+
+ } else if (evt.getSource() == cancel) {
+ /* Cancel button clicked */
+ trust_this_session = false;
+
+ dialog.dispose();
+ }
+ }
+
+ String get_certinfo() {
+ String all = "";
+ String fields[] = {"CN", "OU", "O", "L", "C"};
+ int i;
+ if (serverCerts.length < 1) {
+ all = "";
+ return all;
+ }
+ String cert = serverCerts[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;
+ }
+}
diff -x VncCanvas.java -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 2006-03-27 22:20:19.000000000 -0500
@@ -87,6 +87,7 @@
int deferScreenUpdates;
int deferCursorUpdates;
int deferUpdateRequests;
+ boolean disableSSL;
// Reference to this applet for inter-applet communication.
public static java.applet.Applet refApplet;
@@ -626,6 +627,12 @@
// SocketFactory.
socketFactory = readParameter("SocketFactory", false);
+
+ // SSL
+ disableSSL = false;
+ str = readParameter("DisableSSL", false);
+ if (str != null && str.equalsIgnoreCase("Yes"))
+ disableSSL = true;
}
public String readParameter(String name, boolean required) {