/hg/icedtea-web: PR1161: X509VariableTrustManager does not work ...

dbhole at icedtea.classpath.org dbhole at icedtea.classpath.org
Mon Sep 17 13:40:31 PDT 2012


changeset 9d46cc3428eb in /hg/icedtea-web
details: http://icedtea.classpath.org/hg/icedtea-web?cmd=changeset;node=9d46cc3428eb
author: Deepak Bhole <dbhole at redhat.com>
date: Mon Sep 17 16:40:25 2012 -0400

	PR1161: X509VariableTrustManager does not work correctly with OpenJDK7


diffstat:

 ChangeLog                                                            |   30 ++
 Makefile.am                                                          |    3 +
 NEWS                                                                 |    1 +
 acinclude.m4                                                         |    9 +-
 netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java                   |   93 +++++-
 netx/net/sourceforge/jnlp/security/HttpsCertVerifier.java            |    5 +-
 netx/net/sourceforge/jnlp/security/VariableX509TrustManager.java     |  138 ++++++---
 netx/net/sourceforge/jnlp/security/VariableX509TrustManagerJDK6.java |   75 +++++
 netx/net/sourceforge/jnlp/security/VariableX509TrustManagerJDK7.java |  136 +++++++++
 9 files changed, 415 insertions(+), 75 deletions(-)

diffs (truncated from 704 to 500 lines):

diff -r 439f0b1cee5c -r 9d46cc3428eb ChangeLog
--- a/ChangeLog	Fri Sep 07 17:06:08 2012 -0400
+++ b/ChangeLog	Mon Sep 17 16:40:25 2012 -0400
@@ -1,3 +1,33 @@
+2012-09-17  Deepak Bhole <dbhole at redhat.com>
+
+	PR1161: X509VariableTrustManager does not work correctly with OpenJDK7
+	* Makefile.am: If building with JDK 6, don't build
+	VariableX509TrustManagerJDK7.
+	* NEWS: Updated.
+	* acinclude.m4: In addition to setting VERSION_DEFS, also set HAVE_JAVA7
+	if building with JDK7.
+	* netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java (initialize): Use new
+	getSSLSocketTrustManager() method to get the trust manager.
+	(getSSLSocketTrustManager): New method. Depending on runtime JRE version,
+	returns the appropriate trust manager.
+	* netx/net/sourceforge/jnlp/security/HttpsCertVerifier.java: Removed
+	unused tm variable.
+	* netx/net/sourceforge/jnlp/security/VariableX509TrustManager.java: No
+	longer extends com.sun.net.ssl.internal.ssl.X509ExtendedTrustManager.
+	(checkClientTrusted): Renamed to checkTrustClient and removed overloaded
+	implementations.
+	(checkServerTrusted): Renamed to checkTrustServer. Also, modified to
+	accept socket and engine (may be null). Assume that CN is mismatched by
+	default, rather than matched. If explicitly trusted, bypass other checks,
+	including CN mismatch.
+	(checkAllManagers): Modified to accept socket and engine. Modified to work
+	for both JDK6 and JDK7.
+	(getAcceptedIssuers): Make protected (called by others in package).
+	* netx/net/sourceforge/jnlp/security/VariableX509TrustManagerJDK6.java:
+	New class -- X509TrustManager for JDK6.
+	* netx/net/sourceforge/jnlp/security/VariableX509TrustManagerJDK7.java:
+	New class -- X509TrustManager for JDK7.
+
 2012-09-07  Saad Mohammad  <smohammad at redhat.com>
 
 	Added signed jnlp tests for applications with multiple jar resources.
diff -r 439f0b1cee5c -r 9d46cc3428eb Makefile.am
--- a/Makefile.am	Fri Sep 07 17:06:08 2012 -0400
+++ b/Makefile.am	Mon Sep 17 16:40:25 2012 -0400
@@ -348,6 +348,9 @@
 if !WITH_RHINO
 	sed -i '/RhinoBasedPacEvaluator/ d' $@
 endif
+if !HAVE_JAVA7
+	sed -i '/VariableX509TrustManagerJDK7/ d' $@
+endif
 
 stamps/netx.stamp: netx-source-files.txt stamps/bootstrap-directory.stamp
 	mkdir -p $(NETX_DIR)
diff -r 439f0b1cee5c -r 9d46cc3428eb NEWS
--- a/NEWS	Fri Sep 07 17:06:08 2012 -0400
+++ b/NEWS	Mon Sep 17 16:40:25 2012 -0400
@@ -17,6 +17,7 @@
 * Common
   - PR1049: Extension jnlp's signed jar with the content of only META-INF/* is considered
   - PR955: regression: SweetHome3D fails to run
+  - PR1161: X509VariableTrustManager does not work correctly with OpenJDK7
 
 New in release 1.3 (2012-XX-XX):
 * NetX
diff -r 439f0b1cee5c -r 9d46cc3428eb acinclude.m4
--- a/acinclude.m4	Fri Sep 07 17:06:08 2012 -0400
+++ b/acinclude.m4	Mon Sep 17 16:40:25 2012 -0400
@@ -715,9 +715,12 @@
   AC_MSG_RESULT(${JAVA})
   AC_SUBST(JAVA)
   JAVA_VERSION=`$JAVA -version 2>&1 | sed -n '1s/@<:@^"@:>@*"\(.*\)"$/\1/p'`
-  case "${JAVA_VERSION}" in
-    1.7*) VERSION_DEFS='-DHAVE_JAVA7';;
-  esac
+  HAVE_JAVA7=`echo $JAVA_VERSION | awk '{if ($(0) >= 1.7) print "yes"}'`
+  if  ! test -z "$HAVE_JAVA7" ; then
+    VERSION_DEFS='-DHAVE_JAVA7'
+  fi
+
+  AM_CONDITIONAL([HAVE_JAVA7], test x"${HAVE_JAVA7}" = "xyes" )
   AC_SUBST(VERSION_DEFS)
 ])
 
diff -r 439f0b1cee5c -r 9d46cc3428eb netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java
--- a/netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java	Fri Sep 07 17:06:08 2012 -0400
+++ b/netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java	Mon Sep 17 16:40:25 2012 -0400
@@ -16,38 +16,59 @@
 
 package net.sourceforge.jnlp.runtime;
 
-import java.io.*;
+import java.awt.EventQueue;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
 import java.net.Authenticator;
 import java.net.ProxySelector;
 import java.nio.channels.FileChannel;
 import java.nio.channels.FileLock;
-import java.awt.*;
-import java.text.*;
-import java.util.*;
+import java.security.AllPermission;
+import java.security.KeyStore;
+import java.security.Policy;
+import java.security.Security;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.text.MessageFormat;
 import java.util.List;
-import java.security.*;
-import javax.jnlp.*;
+import java.util.ResourceBundle;
+
+import javax.jnlp.ServiceManager;
 import javax.naming.ConfigurationException;
 import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.KeyManagerFactory;
 import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLSocket;
 import javax.net.ssl.SSLSocketFactory;
 import javax.net.ssl.TrustManager;
 import javax.swing.UIManager;
 import javax.swing.text.html.parser.ParserDelegator;
 
-import sun.net.www.protocol.jar.URLJarFile;
-
-import net.sourceforge.jnlp.*;
+import net.sourceforge.jnlp.DefaultLaunchHandler;
+import net.sourceforge.jnlp.GuiLaunchHandler;
+import net.sourceforge.jnlp.LaunchHandler;
+import net.sourceforge.jnlp.Launcher;
 import net.sourceforge.jnlp.browser.BrowserAwareProxySelector;
-import net.sourceforge.jnlp.cache.*;
+import net.sourceforge.jnlp.cache.CacheUtil;
+import net.sourceforge.jnlp.cache.DefaultDownloadIndicator;
+import net.sourceforge.jnlp.cache.DownloadIndicator;
+import net.sourceforge.jnlp.cache.UpdatePolicy;
 import net.sourceforge.jnlp.config.DeploymentConfiguration;
 import net.sourceforge.jnlp.security.JNLPAuthenticator;
 import net.sourceforge.jnlp.security.KeyStores;
 import net.sourceforge.jnlp.security.SecurityDialogMessageHandler;
 import net.sourceforge.jnlp.security.VariableX509TrustManager;
-import net.sourceforge.jnlp.services.*;
-import net.sourceforge.jnlp.util.*;
+import net.sourceforge.jnlp.services.XServiceManagerStub;
+import net.sourceforge.jnlp.util.FileUtils;
+import net.sourceforge.jnlp.util.TeeOutputStream;
+import sun.net.www.protocol.jar.URLJarFile;
 
 /**
  * Configure and access the runtime environment.  This class
@@ -223,7 +244,7 @@
             KeyStore ks = KeyStores.getKeyStore(KeyStores.Level.USER, KeyStores.Type.CLIENT_CERTS);
             KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
             kmf.init(ks, KeyStores.getPassword());
-            TrustManager[] trust = new TrustManager[] { VariableX509TrustManager.getInstance() };
+            TrustManager[] trust = new TrustManager[] { getSSLSocketTrustManager() };
             context.init(kmf.getKeyManagers(), trust, null);
             sslSocketFactory = context.getSocketFactory();
 
@@ -248,6 +269,52 @@
     }
 
     /**
+     * Returns a TrustManager ideal for the running VM.
+     *
+     * @return TrustManager the trust manager to use for verifying https certificates
+     */
+    private static TrustManager getSSLSocketTrustManager() throws
+                                ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException {
+
+        try {
+
+            Class<?> trustManagerClass;
+            Constructor<?> tmCtor = null;
+
+            if (System.getProperty("java.version").startsWith("1.6")) { // Java 6
+                try {
+                    trustManagerClass = Class.forName("net.sourceforge.jnlp.security.VariableX509TrustManagerJDK6");
+                 } catch (ClassNotFoundException cnfe) {
+                     System.err.println("Unable to find class net.sourceforge.jnlp.security.VariableX509TrustManagerJDK6");
+                     return null;
+                 }
+            } else { // Java 7 or more (technically could be <= 1.5 but <= 1.5 is unsupported)
+                try {
+                    trustManagerClass = Class.forName("net.sourceforge.jnlp.security.VariableX509TrustManagerJDK7");
+                 } catch (ClassNotFoundException cnfe) {
+                     System.err.println("Unable to find class net.sourceforge.jnlp.security.VariableX509TrustManagerJDK7");
+                     return null;
+                 }
+            }
+
+            Constructor<?>[] tmCtors = trustManagerClass.getDeclaredConstructors();
+            tmCtor = tmCtors[0];
+
+            for (Constructor<?> ctor : tmCtors) {
+                if (tmCtor.getGenericParameterTypes().length == 0) {
+                    tmCtor = ctor;
+                    break;
+                }
+            }
+
+            return (TrustManager) tmCtor.newInstance();
+        } catch (RuntimeException e) {
+            System.err.println("Unable to load JDK-specific TrustManager. Was this version of IcedTea-Web compiled with JDK6?");
+            throw e;
+        }
+    }
+
+    /**
      * This must NOT be called form the application ThreadGroup. An application
      * can inject events into its {@link EventQueue} and bypass the security
      * dialogs.
diff -r 439f0b1cee5c -r 9d46cc3428eb netx/net/sourceforge/jnlp/security/HttpsCertVerifier.java
--- a/netx/net/sourceforge/jnlp/security/HttpsCertVerifier.java	Fri Sep 07 17:06:08 2012 -0400
+++ b/netx/net/sourceforge/jnlp/security/HttpsCertVerifier.java	Mon Sep 17 16:40:25 2012 -0400
@@ -59,7 +59,6 @@
 
 public class HttpsCertVerifier implements CertVerifier {
 
-    private VariableX509TrustManager tm;
     private X509Certificate[] chain;
     private String authType;
     private String hostName;
@@ -67,11 +66,9 @@
     private boolean hostMatched;
     private ArrayList<String> details = new ArrayList<String>();
 
-    public HttpsCertVerifier(VariableX509TrustManager tm,
-                             X509Certificate[] chain, String authType,
+    public HttpsCertVerifier(X509Certificate[] chain, String authType,
                              boolean isTrusted, boolean hostMatched,
                              String hostName) {
-        this.tm = tm;
         this.chain = chain;
         this.authType = authType;
         this.hostName = hostName;
diff -r 439f0b1cee5c -r 9d46cc3428eb netx/net/sourceforge/jnlp/security/VariableX509TrustManager.java
--- a/netx/net/sourceforge/jnlp/security/VariableX509TrustManager.java	Fri Sep 07 17:06:08 2012 -0400
+++ b/netx/net/sourceforge/jnlp/security/VariableX509TrustManager.java	Mon Sep 17 16:40:25 2012 -0400
@@ -37,6 +37,9 @@
 
 package net.sourceforge.jnlp.security;
 
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.Socket;
 import java.security.AccessController;
 import java.security.KeyStore;
 import java.security.PrivilegedAction;
@@ -47,25 +50,24 @@
 import java.util.Arrays;
 import java.util.List;
 
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLSocket;
 import javax.net.ssl.TrustManager;
 import javax.net.ssl.TrustManagerFactory;
 import javax.net.ssl.X509TrustManager;
 
+import net.sourceforge.jnlp.runtime.JNLPRuntime;
+import net.sourceforge.jnlp.security.SecurityDialogs.AccessType;
 import sun.security.util.HostnameChecker;
 import sun.security.validator.ValidatorException;
 
-import com.sun.net.ssl.internal.ssl.X509ExtendedTrustManager;
-import net.sourceforge.jnlp.runtime.JNLPRuntime;
-
-import net.sourceforge.jnlp.security.SecurityDialogs.AccessType;
-
 /**
  * This class implements an X509 Trust Manager. The certificates it trusts are
  * "variable", in the sense that it can dynamically, and temporarily support
  * different certificates that are not in the keystore.
  */
 
-final public class VariableX509TrustManager extends X509ExtendedTrustManager {
+final public class VariableX509TrustManager {
 
     /** TrustManagers containing trusted CAs */
     private X509TrustManager[] caTrustManagers = null;
@@ -164,8 +166,8 @@
     /**
      * Check if client is trusted (no support for custom here, only system/user)
      */
-    public void checkClientTrusted(X509Certificate[] chain, String authType,
-                                   String hostName, String algorithm)
+    public void checkTrustClient(X509Certificate[] chain, String authType,
+                                   String hostName)
             throws CertificateException {
 
         boolean trusted = false;
@@ -186,99 +188,125 @@
         throw savedException;
     }
 
-    public void checkClientTrusted(X509Certificate[] chain, String authType)
-            throws CertificateException {
-        checkClientTrusted(chain, authType, null, null);
-    }
-
-    public void checkServerTrusted(X509Certificate[] chain, String authType,
-                                   String hostName, String algorithm)
-            throws CertificateException {
-        checkServerTrusted(chain, authType, hostName, false);
-    }
-
-    public void checkServerTrusted(X509Certificate[] chain, String authType)
-            throws CertificateException {
-        checkServerTrusted(chain, authType, null, null);
-    }
-
     /**
-     * Check if the server is trusted
+     * Check if the server is trusted.
+     *
+     * First, existing stores are checked to see if the certificate is trusted.
+     * Next, if the certificate is not explicitly trusted by the user, a host
+     * name check is performed. The user is them prompted as needed.
      *
      * @param chain The cert chain
      * @param authType The auth type algorithm
-     * @param checkOnly Whether to "check only" i.e. no user prompt, or to prompt for permission
+     * @param hostName The expected hostName that the server should have
+     * @param socket The SSLSocket in use (may be null)
+     * @param ending The SSLEngine in use (may be null)
      */
-    public synchronized void checkServerTrusted(X509Certificate[] chain,
+    public synchronized void checkTrustServer(X509Certificate[] chain,
                              String authType, String hostName,
-                             boolean checkOnly) throws CertificateException {
+                             SSLSocket socket, SSLEngine engine) throws CertificateException {
         CertificateException ce = null;
         boolean trusted = true;
-        boolean CNMatched = true;
+        boolean CNMatched = false;
 
+        // Check trust stores
         try {
-            checkAllManagers(chain, authType);
+            checkAllManagers(chain, authType, socket, engine);
         } catch (CertificateException e) {
             trusted = false;
             ce = e;
         }
 
         // If the certificate is not explicitly trusted, we
-        // need to prompt the user
+        // check host match
         if (!isExplicitlyTrusted(chain, authType)) {
-
-            if (hostName == null) {
-                CNMatched = false;
-            } else {
+            if (hostName != null) {
                 try {
                     HostnameChecker checker = HostnameChecker
                             .getInstance(HostnameChecker.TYPE_TLS);
 
-                    checker.match(hostName, chain[0]); // only need to match @ 0 for
-                                                       // CN
+                    checker.match(hostName, chain[0]); // only need to match @ 0 for CN
 
+                    CNMatched = true;
                 } catch (CertificateException e) {
-                    CNMatched = false;
                     ce = e;
                 }
             }
+        } else {
+            // If it is explicitly trusted, just return right away.
+            return;
         }
 
+        // If it is (not explicitly trusted) AND
+        // ((it is not in store) OR (there is a host mismatch))
         if (!trusted || !CNMatched) {
-            if (checkOnly) {
-                throw ce;
-            } else {
-                if (!isTemporarilyUntrusted(chain[0])) {
-                    boolean b = askUser(chain, authType, trusted, CNMatched, hostName);
+            if (!isTemporarilyUntrusted(chain[0])) {
+                boolean b = askUser(chain, authType, trusted, CNMatched, hostName);
 
-                    if (b) {
-                        temporarilyTrust(chain[0]);
-                    } else {
-                        temporarilyUntrust(chain[0]);
-                    }
+                if (b) {
+                    temporarilyTrust(chain[0]);
+                    return;
+                } else {
+                    temporarilyUntrust(chain[0]);
                 }
+            }
 
-                checkAllManagers(chain, authType);
-            }
+            throw ce;
         }
     }
 
     /**
-     * Check system, user and custom trust manager
+     * Check system, user and custom trust manager.
+     *
+     * This method is intended to work with both, JRE6 and JRE7. If socket
+     * and engine are null, it assumes that the call is for JRE6 (i.e. not
+     * javax.net.ssl.X509ExtendedTrustManager which is Java 7 specific). If
+     * either of those are not null, it will assume that the caTrustManagers
+     * are javax.net.ssl.X509ExtendedTrustManager instances and will
+     * invoke their check methods.
+     *
+     * @param chain The certificate chain
+     * @param authType The authentication type
+     * @param socket the SSLSocket being used for the connection
+     * @param engine the SSLEngine being used for the connection
      */
-    private void checkAllManagers(X509Certificate[] chain, String authType) throws CertificateException {
+    private void checkAllManagers(X509Certificate[] chain, String authType, Socket socket, SSLEngine engine) throws CertificateException {
+
         // first try CA TrustManagers
         boolean trusted = false;
         ValidatorException savedException = null;
         for (int i = 0; i < caTrustManagers.length; i++) {
             try {
-                caTrustManagers[i].checkServerTrusted(chain, authType);
+                if (socket == null && engine == null) {
+                    caTrustManagers[i].checkServerTrusted(chain, authType);
+                } else {
+
+                    try {
+                        Class<?> x509ETMClass = Class.forName("javax.net.ssl.X509ExtendedTrustManager");
+                        if (engine == null) {
+                            Method mcheckServerTrusted = x509ETMClass.getDeclaredMethod("checkServerTrusted", X509Certificate[].class, String.class, Socket.class);
+                            mcheckServerTrusted.invoke(caTrustManagers[i], chain, authType, socket);
+                        } else {
+                            Method mcheckServerTrusted = x509ETMClass.getDeclaredMethod("checkServerTrusted", X509Certificate[].class, String.class, SSLEngine.class);
+                            mcheckServerTrusted.invoke(caTrustManagers[i], chain, authType, engine);
+                        }
+                    } catch (NoSuchMethodException nsme) {
+                        throw new ValidatorException(nsme.getMessage());
+                    } catch (InvocationTargetException ite) {
+                        throw new ValidatorException(ite.getMessage());
+                    } catch (IllegalAccessException iae) {
+                        throw new ValidatorException(iae.getMessage());
+                    } catch (ClassNotFoundException cnfe) {
+                        throw new ValidatorException(cnfe.getMessage());
+                    }
+                }
+
                 trusted = true;
                 break;
             } catch (ValidatorException caex) {
                 savedException = caex;
             }
         }
+
         if (trusted) {
             return;
         }
@@ -332,7 +360,7 @@
         return explicitlyTrusted;
     }
 
-    public X509Certificate[] getAcceptedIssuers() {
+    protected X509Certificate[] getAcceptedIssuers() {
         List<X509Certificate> issuers = new ArrayList<X509Certificate>();
 
         for (int i = 0; i < caTrustManagers.length; i++) {
@@ -394,7 +422,7 @@
             public Boolean run() {
                 return SecurityDialogs.showCertWarningDialog(
                         AccessType.UNVERIFIED, null,
-                        new HttpsCertVerifier(trustManager, chain, authType,
+                        new HttpsCertVerifier(chain, authType,
                                               isTrusted, hostMatched,
                                               hostName));
             }
diff -r 439f0b1cee5c -r 9d46cc3428eb netx/net/sourceforge/jnlp/security/VariableX509TrustManagerJDK6.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/netx/net/sourceforge/jnlp/security/VariableX509TrustManagerJDK6.java	Mon Sep 17 16:40:25 2012 -0400
@@ -0,0 +1,75 @@
+/* VariableX509TrustManagerJDK6.java
+   Copyright (C) 2012 Red Hat, Inc.
+
+This file is part of IcedTea.
+
+IcedTea 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.
+
+IcedTea is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of



More information about the distro-pkg-dev mailing list