JDK-6563297 : X509ExtendedDeployTrustManager NullPointerException
  • Type: Bug
  • Component: deploy
  • Sub-Component: plugin
  • Affected Version: 6u1
  • Priority: P3
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2007-05-30
  • Updated: 2011-02-16
  • Resolved: 2007-05-30
Related Reports
Duplicate :  
Description
FULL PRODUCT VERSION :
Clients:
java version "1.6.0_01"
Java(TM) SE Runtime Environment (build 1.6.0_01-b06)
Java HotSpot(TM) Client VM (build 1.6.0_01-b06, mixed mode, sharing)
Server:
java version "1.5.0_09"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_09-b03)
Java HotSpot(TM) Server VM (build 1.5.0_09-b03, mixed mode)
(As a test, I upgraded the server temporarily to 1.6 and still have the same issue)

ADDITIONAL OS VERSION INFORMATION :
(clients)
Microsoft Windows XP [Version 5.1.2600]
Microsoft Windows [Version 6.0.6000]
(server)
Linux linux11 2.6.16-xms3-rc1 #1 SMP Fri Apr 13 14:30:45 EDT 2007 i686 i686 i386 GNU/Linux

EXTRA RELEVANT SYSTEM CONFIGURATION :
Client to server configuration. Server is running java 1.5.0_09 jdk but the problem occurs even with the latest 1.6.0_01 jdk installed.
Server is running tomcat 5.5.15 (Also tried with latest 5.5.23)
Server is configured to have both http and https with https forced by redirect.

A DESCRIPTION OF THE PROBLEM :
Our existing product consists of Java applets serializing small to very large POJOs to and from a Tomcat server over a https connection. We are using self signed certificates and all has worked well over the last two years using Java versions from 1.4.X to 1.5.X.
Now some of our clients are moving to 1.6 and for those sites that have https forced on, a NPE is being generated down inside com.sun.deploy.security.X509ExtendedDeployTrustManager. If we only use https for login, we never see the exception.

Note: For testing purposes, I downloaded from OpenJDK the fastdebug version of Java 1.6.0_02 and recreated the same problem.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
I do not have a specific test case but I can give a general outline of our setup.

1) Server is Linux Suse 10.1.
2) Server is running 1.5.X or 1.6.0_01 java.
3) Self signed certificates (I've read from other posts that having real certificates does not help)
4) Client applet running 1.6.0_01 or 1.6.0_02.
5) Test with server sending a serialized ArrayList object containing over 3000 rows of data with each row containing up to 10 columns. (the problem doesn't seem to occur as often with smaller amounts of data, but it has)

Once the exception occurs a side effect seems to be the corruption of the java cache such that I must manually delete the directory tree. This isn't always the case, as I guess it depends if the error occurs while the applet is loading a class file or not.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Successful https communication sending serialized objects from server to client, etc..
ACTUAL -
Communication is interrupted and exception generated. This occurs at random times.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
This stack trace was generated by using the binary found at http://www.java.net/download/jdk6/6u2/promoted/b02/binaries/jdk-6u2-ea-bin-b02-windows-i586-debug-12_apr_2007.jar

javax.net.ssl.SSLException: java.lang.NullPointerException
	at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:190)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1591)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1554)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.handleException(SSLSocketImpl.java:1537)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1130)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1107)
	at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:405)
	at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:170)
	at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:836)
	at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:230)
	at com.mycompany.hm.callq.client.common.HttpMessage.sendPostObject(HttpMessage.java:227)
	at com.mycompany.hm.callq.client.common.CallQSerializeData.sendViaHttp(CallQSerializeData.java:132)
	at com.mycompany.hm.callq.client.diagnostics.CallQBaseUITableModel.getActiveCallDetail(CallQBaseUITableModel.java:375)
	at com.mycompany.hm.callq.client.diagnostics.CallQActiveCalls.launch(CallQActiveCalls.java:669)
	at com.mycompany.hm.callq.client.diagnostics.CallQActiveCalls$1.mouseClicked(CallQActiveCalls.java:214)
	at java.awt.AWTEventMulticaster.mouseClicked(AWTEventMulticaster.java:253)
	at java.awt.Component.processMouseEvent(Component.java:6041)
	at javax.swing.JComponent.processMouseEvent(JComponent.java:3265)
	at java.awt.Component.processEvent(Component.java:5803)
	at java.awt.Container.processEvent(Container.java:2058)
	at java.awt.Component.dispatchEventImpl(Component.java:4410)
	at java.awt.Container.dispatchEventImpl(Container.java:2116)
	at java.awt.Component.dispatchEvent(Component.java:4240)
	at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4322)
	at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3995)
	at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3916)
	at java.awt.Container.dispatchEventImpl(Container.java:2102)
	at java.awt.Component.dispatchEvent(Component.java:4240)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:273)
	at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:183)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:173)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:168)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:160)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:121)
Caused by: java.lang.NullPointerException
	at com.sun.deploy.security.X509ExtendedDeployTrustManager.isSupportedAlgorithm(X509ExtendedDeployTrustManager.java:463)
	at com.sun.deploy.security.X509ExtendedDeployTrustManager.checkServerTrusted(X509ExtendedDeployTrustManager.java:303)
	at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:954)
	at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:123)
	at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:516)
	at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:454)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:884)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1096)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1123)
	... 30 more


The above randomly occurs after our applet clients upgrade to 1.6.0_01. This test was used against 1.6.0_02.

Hotspot Log attached seperatly.

REPRODUCIBILITY :
This bug can be reproduced often.

---------- BEGIN SOURCE ----------
The client side code:

    public Object sendPostObject (Serializable obj) throws Exception
    {
        Object o = null;
        ObjectOutputStream out = null;
        InputStream in = null;
        ObjectInputStream result = null;
        String contentType = null;
        HttpURLConnection con  = null;
        
        try
        {
            con = (HttpURLConnection)servlet.openConnection ();
            
            // Prepare for both input and output
            con.setDoInput (true);
            con.setDoOutput (true);
            
            // Turn off caching
            con.setUseCaches (false);
            
            con.setRequestMethod ("POST");
            
            // Set the content type to be application/x-java-serialized-object
            con.setRequestProperty ("Content-Type",
                    "application/x-java-serialized-object");
            
            setHeader ("Accept-Language", java.util.Locale.getDefault ().getLanguage ());
            setHeader (HttpMessage.HTTP_HEADER_LOCALE_LANG, java.util.Locale.getDefault ().getLanguage ());
            setHeader (HttpMessage.HTTP_HEADER_LOCALE_COUNTRY, java.util.Locale.getDefault ().getCountry ());
            setHeader (HttpMessage.HTTP_HEADER_LOCALE_VARIANT, java.util.Locale.getDefault ().getVariant ());
            
            // Send headers
            sendHeaders (con);
            
            // Write the serialized object as post data
            
            out = new ObjectOutputStream (con.getOutputStream ());
            
            out.writeObject (obj);
            out.flush ();
            out.close ();
            
            in = con.getInputStream ();
            
            result = new ObjectInputStream (in);
            o = result.readObject ();
            
            // Communication was successfully established with the Server
            // Update the Session Timers
            SessionMonitor.sessionWasReset ();
            
        }
        catch (Exception e)
        {
            if (DEBUG)
            {
                e.printStackTrace ();
            }
            throw e;
        }
        finally
        {
            try
            {
                if (in != null)
                    in.close ();
                if (result != null)
                    result.close ();
                con.disconnect ();
            }
            catch (Exception na)
            {
            }
        }
        
        return (o);
    }
    
The server side code:
    public void doGet (HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
    {
        // Get or create session object
        HttpSession session = req.getSession();

        CallQArg callqarg;

        Connection connection = null;
        ObjectInputStream input = null;
 
        if (CallQServerUtilities.isSerializedObjectReq (req))
        {
            input = new ObjectInputStream (req.getInputStream ());
        }
        else
        {
            String home = "/";
            RequestDispatcher dispatcher = req.getRequestDispatcher (home);
            dispatcher.forward (req, res);
            return ;
        }

        boolean connectionIdDefined = false;
            
        try
        {
            // Get database connection from connection pool
            connection = dataSource.getConnection();
            
            Object obj = input.readObject();    // Get serialized argument object
            
            if (obj instanceof CallQArg)
            {
                CallQArg cq = (CallQArg)obj;
                if (cq.methodId == CallQArg.GET_CALLS)  // If a diagnostic query
                {
                    // Store connection ID in session object for possible cancellation in DBControlServlet
                    long connectionID = CallQDB.getConnectionID(connection);
                    session.setAttribute(connectionIdKey, new Long(connectionID));
                    connectionIdDefined = true;
                }
            }

            // Process the method call
            callqarg = processInput(connection, obj);
        }
        catch (Exception e)
        {
            // Fill out a CallQArg with exception information.
            callqarg = new CallQArg(-1, e);

            // If the exception was not a canceled query,
            // write information to the log
            if (!(e instanceof CanceledQueryException))
            {
                e.printStackTrace();
            }
        }
        finally
        {
            if (connectionIdDefined)
            {
                session.removeAttribute(connectionIdKey);   // Remove connection ID from session object
            }

            if (connection != null)
            {
                // Return connection to the pool
                try
                {
                    connection.close();
                }
                catch (SQLException e){}

                connection = null;
            }
        }
        
        // If for some reason we do not have a callqarg - create one set with
        // error text etc. This could be error text pulled from a JDBC error
        if (callqarg == null)
        {
            callqarg = new CallQArg (-1, new String ("No response"));
        }
        ObjectOutputStream out = new ObjectOutputStream (res.getOutputStream ());
        out.writeObject (callqarg);
        out.close();
        
        // close the input stream
        if(input != null)
        {
            input.close();
        }
    }
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
1) Do not use https
2) Move client back to 1.5.

Both of which, for some of our customers, is not acceptable.

Release Regression From : 5.0u10
The above release value was the last known release where this 
bug was not reproducible. Since then there has been a regression.